使用C#反射从字典生成动态对象

8

我最近在研究 C# 中的反射,想知道是否可以使用具有键值对的字典来创建一个对象,并且该对象的变量名称为字典中每个键名和它们的键值。

我已经编写了一个方法,可以从字典中提取对象,该字典包含类属性的键和其值,即属性值。

我想知道如何实现这一点。

以下是我的方法,用于从一个对象中提取一个字典:

protected Dictionary<String, String> getObjectProperty(object objeto)
{
    Dictionary<String, String> dictionary = new Dictionary<String, String>();

    Type type = objeto.GetType();
    FieldInfo[] field = type.GetFields();
    PropertyInfo[] myPropertyInfo = type.GetProperties();

    String value = null;

    foreach (var propertyInfo in myPropertyInfo)
    {
        if (propertyInfo.GetIndexParameters().Length == 0)
        {
            value = (string)propertyInfo.GetValue(objeto, null);
            value = value == null ? null : value;
            dictionary.Add(propertyInfo.Name.ToString(), value);
        }
    }

    return dictionary;
}

2
你是指“动态”类型的对象吗?还是创建新类型? - Euphoric
你使用的是哪个版本的.NET框架? - Alessandro D'Andria
对象已经存在,当退出此函数时,我只需要将其结果强制转换为现有对象。(myObject) .NET 4.0 - Elton da Costa
也许这就是你要找的内容:将Dictionary<string, object>转换为匿名对象? - Lipotam
3个回答

12
如果您已经有一个字典,我建议避免使用反射,而是使用DynamicObject
例如:
public class DynamicDictionary : DynamicObject
{
    private readonly Dictionary<string, object> dictionary;

    public DynamicDictionary(Dictionary<string, object> dictionary)
    {
        this.dictionary = dictionary;
    }

    public override bool TryGetMember(
        GetMemberBinder binder, out object result)
    {
        return dictionary.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(
        SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;

        return true;
    }
}

可以按以下方式使用:

dynamic x = new DynamicDictionary(
    new Dictionary<string, object> {{"Name", "Peter"}});

Console.WriteLine(x.Name);

3

我不确定这是否是您要查找的内容,但根据您的问题,我认为您想要从字典中获取类型并在运行时实例化类型,这将通过提供一个键来实现。

如果是这样,那么您可以创建以下类,该类将保存字符串键值对和类型,该类型将被实例化。

class DictionaryActivator
{
    Dictionary<string, Type> Dictionary = new Dictionary<string, Type>();

    public DictionaryActivator()
    {
        Dictionary.Add("MyCar", typeof(Car));
        Dictionary.Add("MyHouse", typeof(House));
        Dictionary.Add("MyFruit", typeof(Fruit));
        Dictionary.Add("MyComputer", typeof(Computer));
    }

    public T GetInstance<T>(string type, params object[] parameters)
    {
        if (parameters.Count() == 0)
        {
            return (T)Activator.CreateInstance(Dictionary[type]);
        }
        else
        {
            return (T)Activator.CreateInstance(Dictionary[type], parameters.ToArray());
        }
    }
}

您可以创建四个测试类来测试这个设置。
class House
{
    public int Number = 25;
}

class Car
{
    public double Price = 50000;
}

class Fruit
{
    public string Name = "Apple";
}

class Computer
{
    public string Cpu { get; set; }
    public string Gpu { get; set; }

    public Computer(string cpu, string gpu)
    {
        Cpu = cpu;
        Gpu = gpu;
    }
}

一旦完成此步骤,您可以运行以下代码来获取字典中的所有类型,实例化它们并将它们转换为适当的类型。正如您可能注意到的那样,最后一个 Computer 示例向您展示了如何向新创建的实例中添加多个参数(在本例中为两个),并将其作为类型 object 的实例返回。
最后,您可以将其转换为 Computer 类型,以便检查构造函数参数是否实际传递给相应的属性。
class Program
{
    static void Main()
    {
        var source = new DictionaryActivator();

        Console.WriteLine(source.GetInstance<Car>("MyCar").Price);
        Console.WriteLine(source.GetInstance<House>("MyHouse").Number);
        Console.WriteLine(source.GetInstance<Fruit>("MyFruit").Name);

        var computer = source.GetInstance<object>("MyComputer", "Fast CPU", "Fast GPU");

        Console.WriteLine((computer as Computer).Cpu);
        Console.WriteLine((computer as Computer).Gpu);

        Console.Read();
    }
}

我可以创建一个类型为Object的对象,并添加例如两个变量及其值,并返回它吗? - Elton da Costa
我已经编辑了我的答案,所以是的,你可以完全这样做。只需将您想要传递的参数传递给新实例,并使用在GetInstance<T>(string, params object[])方法上定义的泛型类型将其转换为对象。 - Mario Stopfer

2

由于ExpandoObject是一个字典,因此您可以使用此扩展函数:

public static object With(this IDictionary<string, object> obj, IDictionary<string,object> additionalProperties)
{
  foreach (var name in additionalProperties.Keys)
    obj[name] = additionalProperties[name];
  return obj;
}

使用方法:

var dynamicObj = new System.Dynamic.ExpandoObject().With(myDictionary);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接