您的位置:首页 > 编程语言 > C#

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

2017-11-06 17:43 585 查看
最近在写工业机械臂控制的代码,需要实现如下的一个功能:

将机械臂需要执行的函数与输入参数按照顺序保存成文件,加载文件后能够直接命令机械手进行动作。

界面使用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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐