C# 利用函数反射、XML序列化/反序列化保存函数执行与输入参数列表

最近在写工业机械臂控制的代码,需要实现如下的一个功能:
将机械臂需要执行的函数与输入参数按照顺序保存成文件,加载文件后能够直接命令机械手进行动作。
界面使用winform进行开发。函数名与参数的保存、加载的部分,考虑到日后函数的增删,使用了函数反射+XML序列化/反序列一个方案。

这部分用Console模拟一下。

先编写一个类 Coordinate 来表示坐标,类中有三个属性X,Y,Z分别代表X,Y,Z坐标值。

    public class Coordinate
    {
        /// <summary>
        /// X坐标值
        /// </summary>
        public double X { get; set; }
        /// <summary>
        /// Y坐标值
        /// </summary>
        public double Y { get; set; }
        /// <summary>
        /// Z坐标值
        /// </summary>
        public double Z { get; set; }

        public override string ToString()
        {
            return "X:" + X + "|Y:" + Y + "|Z:" + Z;
        }

        public void SetCoordinate(double x , double y, double z)
        {
            X = x;
            Y = y;
            Z = z;
        }

        public static Coordinate operator +(Coordinate coor1 , Coordinate coor2)
        {
            return new Coordinate() { X = coor1.X + coor2.X, Y = coor1.Y + coor2.Y, Z = coor1.Z + coor2.Z };
        }

        public static Coordinate operator -(Coordinate coor1, Coordinate coor2)
        {
            return new Coordinate() { X = coor1.X - coor2.X, Y = coor1.Y - coor2.Y, Z = coor1.Z - coor2.Z };
        }

        private static readonly Coordinate _originalCoordinate = new Coordinate { X = 0, Y = 0, Z = 0 };

        /// <summary>
        /// 原点坐标
        /// </summary>
        public static Coordinate OriginalCoordinate { get { return _originalCoordinate; } }
    }

编写一个类 Person 来模拟机械手臂,类中有如下几种方法:

    public class Person
    {
        /// <summary>
        /// 当前坐标点
        /// </summary>
        public Coordinate CurrentCoordinate { get; private set; }

        public Person()
        {
            CurrentCoordinate = Coordinate.OriginalCoordinate;
        }

        /// <summary>
        /// 以指定移动到目标地点
        /// </summary>
        /// <param name="coorDst"> 目的坐标点 </param>
        /// <param name="speed"> 速度 </param>
        public void MoveToDestination(Coordinate coorDst , int speed)
        {
            Console.WriteLine("以速度:" + speed + "移动到点:" + coorDst.ToString());
            CurrentCoordinate = coorDst;
            Console.WriteLine("当前位置:" + CurrentCoordinate.ToString());
        }

        /// <summary>
        /// 移动一定偏移坐标
        /// </summary>
        /// <param name="coorOffset">坐标偏移量</param>
        /// <param name="speed">速度</param>
        public void MoveOffset(Coordinate coorOffset , int speed)
        {
            Console.WriteLine("以速度:" + speed + "移动偏移坐标:" + coorOffset.ToString());
            CurrentCoordinate += coorOffset;
            Console.WriteLine("当前位置:" + CurrentCoordinate.ToString());
        }

        /// <summary>
        /// 退回原点
        /// </summary>
        /// <param name="speed">速度</param>
        public void BackToOriginalPoint(int speed)
        {
            CurrentCoordinate = Coordinate.OriginalCoordinate;
            Console.WriteLine("以速度:" + speed + "回到原点");
        }
    }

编写一个类 Parameter 用来保存函数的单个输入参数,类中有两个属性 Type : ParamType 与 Object : Value 。ParamType 表示参数值的类型,Value 表示输入参数的值。因为Xml序列化/反序列化需要参数值的类型,所以需要保存输入参数的类型 ParamType。并且为了降低耦合度,使用Object对象来保存参数值。实现IXmlSerializable接口来自定义序列化的过程(object对象无法自行实现序列化/反序列化)。

    public class Parameter :  IXmlSerializable
    {
        /// <summary>
        /// 参数类型
        /// </summary>
        public Type ParamType { get; set; }

        /// <summary>
        /// 参数值
        /// </summary>
        public object Value { get; set; }

        XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }

        void IXmlSerializable.ReadXml(XmlReader reader)
        {
            if (reader.IsEmptyElement)
                return;
            reader.Read();

            XmlSerializer xs = new XmlSerializer(typeof(string));
            reader.ReadStartElement("ParamType");
            string strType = (string)xs.Deserialize(reader);
            string strAssembly = strType.Split('.')[0];
            //如果是.net里面包含的Type 直接使用Type.GetType接口
            if (strAssembly == "System") 
            {
                ParamType = Type.GetType(strType);
            }
            else
            { 
                //如果是其他程序集内的类型,需要加载程序集,然后利用反射获取参数类型
                Assembly assembly = Assembly.Load(strAssembly);
                ParamType = assembly.GetType(strType);
            }

            xs = new XmlSerializer(ParamType);
            reader.ReadStartElement("Value");
            Value = xs.Deserialize(reader);
            reader.ReadEndElement();

            reader.ReadEndElement();
        }

        void IXmlSerializable.WriteXml(XmlWriter writer)
        {
            writer.WriteStartElement("ParamType");
            //这边需要将Type保存成字符串,直接序列化 Type 会有异常(暂时不清楚为什么)
            XmlSerializer xs = new XmlSerializer(typeof(string));
            xs.Serialize(writer, ParamType.ToString());
            writer.WriteEndElement();

            writer.WriteStartElement("Value");
            xs = new XmlSerializer(ParamType);
            xs.Serialize(writer, Value);
            writer.WriteEndElement();
        }
    }

编写一个类 FunctionInfo ,类中有两个属性 string : FunctionName 与 Parameter[]:Parameters ,分别用来保存函数名与函数的输入参数。

    public class FunctionInfo
    {
        /// <summary>
        /// 函数名称
        /// </summary>
        public string FunctionName { get; set; }

        /// <summary>
        /// 参数
        /// </summary>
        [XmlArray]
        public Parameter[] Parameters { get; set; }
    }

最后再编写一个类,用来保存整个函数事务列表

    public class Actions
    {
        [XmlArray]
        public FunctionInfo[] FunctionInofs { get; set; }
    }

下面是Main函数的执行代码:

        static void Main(string[] args)
        {
            //新建一个事务列表
            Actions actions = new Actions();
            actions.FunctionInofs = new FunctionInfo[3];
            //函数1 MoveToDestination
            actions.FunctionInofs[0] = new FunctionInfo()
            {
                FunctionName = "MoveToDestination",
                Parameters = new Parameter[]
                {
                    new Parameter { Value = new Coordinate { X = 1, Y = 2, Z = 3}, ParamType = typeof(Coordinate) },
                    new Parameter {  Value = 10, ParamType = typeof(int)},
                }
            };

            //函数2 MoveOffset
            actions.FunctionInofs[1] = new FunctionInfo()
            {
                FunctionName = "MoveOffset",
                Parameters = new Parameter[]
                {
                    new Parameter { Value = new Coordinate { X = 1, Y = 2, Z = 3}, ParamType = typeof(Coordinate) },
                    new Parameter {  Value = 5, ParamType = typeof(int)},
                }
            };

            //函数3 BackToOriginalPoint
            actions.FunctionInofs[2] = new FunctionInfo()
            {
                FunctionName = "BackToOriginalPoint",
                Parameters = new Parameter[]
                {
                    new Parameter {  Value = 2, ParamType = typeof(int)},
                }
            };

            //保存到Xml文件
            using (XmlWriter writer = XmlWriter.Create(System.Environment.CurrentDirectory + "\\functions.xml"))
            {
                XmlSerializer xs = new XmlSerializer(typeof(Actions));
                xs.Serialize(writer, actions);
            }

            //从Xml文件反序列化
            using (XmlReader reader = XmlReader.Create(System.Environment.CurrentDirectory + "\\functions.xml"))
            {
                XmlSerializer xs = new XmlSerializer(typeof(Actions));
                actions = (Actions)xs.Deserialize(reader);
            }

            //定义一个Person
            Person person = new Person();
            //获取类型
            Type type = typeof(Person); //这里需要根据Person程序集的位置适当修改获取Type的方式
            //依次执行函数
            foreach (var action in actions.FunctionInofs)
            {
                var mi = type.GetMethod(action.FunctionName, BindingFlags.Public | BindingFlags.Instance);
                mi.Invoke(person, action.Parameters.Select(x => x.Value).ToArray());
            }
            Console.ReadLine();
        }
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值