C#使用reflection来创建结构

我目前正在编写一些代码,使用c#中的reflection将常规对象保存到XML。

问题是当读取某些对象中的XML是结构体时,我无法弄清楚如何初始化结构体。 对于我可以使用的课程

ConstructorInfo constructor = SomeClass.GetConstructor(Type.EmptyTypes); 

但是,对于结构体,没有没有参数的构造函数,因此上面的代码将构造函数设置为null。 我也试过了

 SomeStruct.TypeInitializer.Invoke(null) 

但是这会抛出一个元素。 谷歌没有提供有希望的点击率。 任何帮助,将不胜感激。

如果值是结构,则它们可能是不可变的 – 因此您不希望调用无参数构造函数,而是使用适当的值作为构造函数参数的构造函数。

如果结构不是不可变的,那么尽可能快地远离它们,如果你可以……但是如果你必须这样做,那么使用Activator.CreateInstance(SomeClass) 。 当您使用reflection在值类型上设置属性或字段时,您必须非常小心 – 如果不小心,您最终将创建副本,更改该副本上的值,然后将其丢弃。 我怀疑如果你一直使用盒装版本,你会没事的:

 using System; // Mutable structs - just say no... public struct Foo { public string Text { get; set; } } public class Test { static void Main() { Type type = typeof(Foo); object value = Activator.CreateInstance(type); var property = type.GetProperty("Text"); property.SetValue(value, "hello", null); Foo foo = (Foo) value; Console.WriteLine(foo.Text); } } 

CreateInstance不会帮助您使用没有明确定义的构造函数的结构。

 FormatterServices.GetUninitializedObject(Type type); 

这可以解决空白结构问题。

只是添加 – 使用不可变的结构,您可能必须与构造函数进行参数匹配。 不幸的是,当有多个构造时,这很棘手,特别是因为某些类型具有单独的静态“Create”方法而不是公共构造函数。 但假设您已完成匹配,您仍然可以使用Activator.CreateInstance

  Type type = typeof(Padding); // just an example object[] args = new object[] {1,2,3,4}; object obj = Activator.CreateInstance(type, args); 

但是 – 选择构造函数的代码(上面有3个……)并不容易。 您可以说“选择最复杂的”,然后尝试将参数名称与属性名称匹配(不区分大小写)…

一个天真的例子:

 static void Main() { Dictionary propertyBag = new Dictionary(); // these are the values from your xml propertyBag["Left"] = 1; propertyBag["Top"] = 2; propertyBag["Right"] = 3; propertyBag["Bottom"] = 4; // the type to create Type type = typeof(Padding); object obj = CreateObject(type, propertyBag); } static object CreateObject(Type type, IDictionary propertyBag) { ConstructorInfo[] ctors = type.GetConstructors(); // clone the property bag and make it case insensitive propertyBag = new Dictionary( propertyBag, StringComparer.OrdinalIgnoreCase); ConstructorInfo bestCtor = null; ParameterInfo[] bestParams = null; for (int i = 0; i < ctors.Length; i++) { ParameterInfo[] ctorParams = ctors[i].GetParameters(); if (bestCtor == null || ctorParams.Length > bestParams.Length) { bestCtor = ctors[i]; bestParams = ctorParams; } } if (bestCtor == null) throw new InvalidOperationException( "Cannot create - no constructor"); object[] args = new object[bestParams.Length]; for (int i = 0; i < bestParams.Length; i++) { args[i] = propertyBag[bestParams[i].Name]; propertyBag.Remove(bestParams[i].Name); } object obj = bestCtor.Invoke(args); // TODO: if we wanted, we could apply any unused keys in propertyBag // at this point via properties return obj; }