C# 利用函数反射、XML序列化/反序列化保存函数执行与输入参数列表
2017-11-06 17:43
585 查看
最近在写工业机械臂控制的代码,需要实现如下的一个功能:
将机械臂需要执行的函数与输入参数按照顺序保存成文件,加载文件后能够直接命令机械手进行动作。
界面使用winform进行开发。函数名与参数的保存、加载的部分,考虑到日后函数的增删,使用了函数反射+XML序列化/反序列一个方案。
这部分用Console模拟一下。
先编写一个类 Coordinate 来表示坐标,类中有三个属性X,Y,Z分别代表X,Y,Z坐标值。
编写一个类 Person 来模拟机械手臂,类中有如下几种方法:
编写一个
beb7
类 Parameter 用来保存函数的单个输入参数,类中有两个属性 Type : ParamType 与 Object : Value 。ParamType 表示参数值的类型,Value 表示输入参数的值。因为Xml序列化/反序列化需要参数值的类型,所以需要保存输入参数的类型 ParamType。并且为了降低耦合度,使用Object对象来保存参数值。实现IXmlSerializable接口来自定义序列化的过程(object对象无法自行实现序列化/反序列化)。
编写一个类 FunctionInfo ,类中有两个属性 string : FunctionName 与 Parameter[]:Parameters ,分别用来保存函数名与函数的输入参数。
最后再编写一个类,用来保存整个函数事务列表
下面是Main函数的执行代码:
将机械臂需要执行的函数与输入参数按照顺序保存成文件,加载文件后能够直接命令机械手进行动作。
界面使用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 + "回到原点"); } }
编写一个
beb7
类 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(); } }
相关文章推荐
- C#动态执行类库中的函数:利用反射实现(js)Eval,asp(Execute)功能
- 数据库操作_连接SQL Server数据库示例;连接ACCESS数据库;连接到 Oracle 数据库示例;SqlCommand 执行SQL命令示例;SqlDataReader 读取数据示例;使用DataAdapter填充数据到DataSet;使用DataTable存储数据库表;将数据库数据填充到 XML 文件;10 使用带输入参数的存储过程;11 使用带输入、输出参数的存储过程示;12 获得数据库中表的数目和名称;13 保存图片到SQL Server数据库示例;14 获得插入记录标识号;Exce
- C#动态执行函数:利用反射实现
- C#利用反射实现(js)Eval,asp(Execute)功能 动态执行类库中的函数
- C#动态执行函数:利用反射实现
- 关于在C#中,将XML源文件序列化和反序列化的问题
- c#解决Nullable类型的转换 (包含DataContract的序列化和反序列化以及 该例子应用在反射属性setvalue的时候有用)
- C#实现XML和实体类之间相互转换:序列化和反序列化
- 【语言-C#】c# 工程文件的保存(序列化Serialize)与打开(反序列化Deseriali)
- 对类参数的序列化和反序列化XML
- c# XML和实体类之间相互转换(序列化和反序列化)
- ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml) 用javascript在客户端删除某一个cookie键值对 input点击链接另一个页面,各种操作。 C# 往线程里传参数的方法总结 TCP/IP 协议 用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图 (转)值得学习百度开源70+项目
- C# XmlSerializer 对象的Xml序列化和反序列化
- c# XML和实体类之间相互转换(序列化和反序列化)
- 对于qt5的信号机制的一点参考,然后利用模板实现:在新线程执行可变函数参数的调用
- .NET/C#利用反射调用含ref或out参数的方法示例代码
- c# XML和实体类之间相互转换(序列化和反序列化)
- java中利用反射机制得到一个类的所有构造方法,成员方法机器参数的列表
- 创建函数利用可变参数列表的形式模拟实现printf的功能
- C#中利用LINQ to XML与反射把任意类型的泛型集合转换成XML格式字符串的方法