使用反射来创建一个struct C#(C# using reflection to create a

2019-06-23 11:13发布

我目前正在写一些代码来保存一般对象在C#中使用反射XML。

读操作时的XML回来一些对象是结构,我无法工作,如何初始化结构的问题。 对于一类,我可以使用

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

然而,对于一个结构,没有构造函数没有参数所以上面的代码集的构造函数为空。 我也试过

SomeStruct.TypeInitializer.Invoke(null)

但是这将引发memberaccessexception。 谷歌没有给出有希望的命中。 任何帮助,将不胜感激。

Answer 1:

如果值是结构,他们很可能是不变的-所以你不想要调用参数的构造函数做的,但其中一个采取适当的值作为构造函数的参数。

如果结构并非一成不变,然后运行远离他们尽可能快的,如果可以的话......但如果你绝对做到这一点,那么使用Activator.CreateInstance(SomeClass) 。 你必须要非常小心,当你使用反射,虽然设定的值类型的属性或字段 - 没有这种照顾,你最终会创建一个副本,在该副本更改值,然后把它扔了。 我怀疑 ,如果你用的是盒装版本的整个工作,你会好起来的:

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);
    }
}


Answer 2:

的CreateInstance不会帮助你,没有明确定义的构造结构。

FormatterServices.GetUninitializedObject(Type type);

这确实与空白结构的伎俩。



Answer 3:

我想补充- 万古不易的结构,你可能需要做的参数匹配的构造函数。 不幸的是,这是非常棘手的时候可以有多种结构,尤其是因为某些类型有一个单独的静态“创建”方法,而不是公共构造函数。 但是, 假设你已经做了匹配,你仍然可以使用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<string, object> propertyBag =
        new Dictionary<string, object>();
    // 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<string,object> propertyBag)
{
    ConstructorInfo[] ctors = type.GetConstructors();
    // clone the property bag and make it case insensitive
    propertyBag = new Dictionary<string, object>(
        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;
}


文章来源: C# using reflection to create a struct
标签: c# reflection