C#使用反射创建结构体
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1005336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# using reflection to create a struct
提问by
I am currently writing some code to save general objects to XML using reflection in c#.
我目前正在编写一些代码来使用 c# 中的反射将一般对象保存到 XML。
The problem is when reading the XML back in some of the objects are structs and I can't work out how to initialise the struct. For a class I can use
问题是在某些对象中读取 XML 时是结构,我无法弄清楚如何初始化该结构。对于我可以使用的课程
ConstructorInfo constructor = SomeClass.GetConstructor(Type.EmptyTypes);
however, for a struct, there is no constructor which takes no parameters so the above code sets constructor to null. I also tried
但是,对于结构,没有不带参数的构造函数,因此上面的代码将构造函数设置为 null。我也试过
SomeStruct.TypeInitializer.Invoke(null)
but this throws a memberaccessexception. Google gives no promising hits. Any help would be appreciated.
但这会引发成员访问异常。谷歌没有给出有希望的点击。任何帮助,将不胜感激。
回答by Jon Skeet
If the values are structs, they're likelyto be immutable - so you don't want to call a parameterless constructor, but the one which takes the appropriate values as constructor arguments.
如果值是结构体,则它们很可能是不可变的——因此您不想调用无参数构造函数,而是调用将适当值作为构造函数参数的构造函数。
If the structs aren'timmutable, then run away from them as fast as possible, if you can... but if you absolutely haveto do this, then use Activator.CreateInstance(SomeClass)
. You'll have to be very careful when you use reflection to set properties or fields on the value type though - without that care, you'll end up creating a copy, changing the value on that copy, and then throwing it away. I suspectthat if you work with a boxed version throughout, you'll be okay:
如果结构不是一成不变的,那么尽可能快地远离它们,如果可以的话……但如果你绝对必须这样做,那么使用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);
}
}
回答by Marc Gravell
Just to add - with immutablestructs, you are likely to have to do parameter matching to the constructor. Unfortunately this is tricky when there can be multiple constructs, and especially since some types have a separate static "Create" method instead of a public constructor. But assumingyou've done the matching, you can still use Activator.CreateInstance
:
只是添加 - 使用不可变结构,您可能必须对构造函数进行参数匹配。不幸的是,当存在多个构造时,这很棘手,尤其是因为某些类型具有单独的静态“Create”方法而不是公共构造函数。但是假设您已经完成匹配,您仍然可以使用Activator.CreateInstance
:
Type type = typeof(Padding); // just an example
object[] args = new object[] {1,2,3,4};
object obj = Activator.CreateInstance(type, args);
However - the code to pick a constructor (the above has 3...) isn't easy. You could say "pick the most complex" and then attempt to match parameter names to property names (case insensitive)...
但是 - 选择构造函数的代码(上面有 3 个......)并不容易。您可以说“选择最复杂的”,然后尝试将参数名称与属性名称匹配(不区分大小写)...
A na?ve example:
一个简单的例子:
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;
}
回答by boskicthebrain
CreateInstance will not help you with structs with no explicitly defined constructors.
CreateInstance 不会帮助您处理没有明确定义的构造函数的结构。
FormatterServices.GetUninitializedObject(Type type);
This does the trick with blank structs.
这对空白结构有效。