【问题标题】:Simple Generics -- Is this possible Method<typeof(T)>()?简单的泛型——这可能是 Method<typeof(T)>() 吗?
【发布时间】:2011-04-04 12:12:03
【问题描述】:

我正在尝试创建一个通用映射函数,它获取字典及其子类的值,并使用反射将它们映射到 T 中的字段。在对象 T 中,有必须钻入的子对象,通过递归,这似乎是一个非常简单的概念。但是我被卡住了——我不确定这是否是泛型的限制,或者是我做错了什么。这是我的功能:

我用以下方式调用第一个实例。

OrderDetails readyOrder = Tools.MapStruct<OrderDetails>(order);

*XmlRpcStruct 是一个字典,子类总是 XmlRpcStruct 的 -- 包含

    public static T MapStruct<T>(XmlRpcStruct xmlRpcStruct) where T : new()
    {
        T map = new T();
        foreach (DictionaryEntry entry in xmlRpcStruct)
        {
            XmlRpcStruct entryStruct = (XmlRpcStruct)entry.Value;
            foreach (DictionaryEntry subEntry in entryStruct)
            {
                if (subEntry.Value.GetType() != typeof(XmlRpcStruct))
                {
                    var prop = map.GetType().GetField(subEntry.Key.ToString());
                    prop.SetValue(map, subEntry.Value);
                }
                else
                {
                    var prop = map.GetType().GetField(subEntry.Key.ToString());
                    ERROR -->prop.SetValue(map, MapStruct<prop.GetType()> (subEntry.Value));
                }
            }
        }
        return map;
    }

例如,我可以有一个包含以下数据的字典:

键----值

第一——约翰

最后---史密斯

年龄----45

地址字典对象

...还有一个对象:

obj.First(字符串)

obj.Last(字符串)

obj.Age (int)

obj.Address (AddressType)

我正在使用对象中的类型来确定名称值对中的 Dictionary 对象应该被转换为什么。

我需要能够在我的字典中动态获取子项的类型并递归调用相同的函数。我哪里错了?

【问题讨论】:

  • 那么,subEntry.Value 是什么?
  • 我不懂任何 C#,但我知道一件事:泛型是一个编译时概念:编译时,会检查所有类型的传入对象并强制转换所有类型的传出对象 - 从泛型不再存在,一旦编译,将不知道所讨论对象的类型。我认为 typeof 在编译时没有处理,所以在泛型中使用它没有什么意义(或者可能是不可能的,我不知道)。
  • 贾斯珀:你错了。这适用于 Java 泛型和 C++ 模板,但不适用于 C# 泛型。您还能如何实例化在程序集中编译的通用函数?
  • @DeadMG:我认为泛型作为一个概念是正确的(我有兴趣了解 C# 如何实现泛型),但我可能错了。但是,当涉及到 C++ 模板时,您绝对是错误的——它们不被称为泛型是有原因的,因为它们以完全不同的方式工作(具有其他弱点、优势和可能性)。
  • @Jasper:我完全了解 C++ 模板的工作原理。它们只是编译时的。我从来没有说别的。 C# 泛型不是。

标签: c# generics reflection recursion


【解决方案1】:

为什么不包起来呢?无论如何它都在使用反射......

public static T MapStruct<T>(XmlRpcStruct xmlRpcStruct) where T : class, new()
{
    return (T)MapStructInternal(typeof(T), xmlRpcStruct);
}

private static object MapStructInternal(Type t, XmlRpcStruct xmlRpcStruct)
{
    object map = t.GetConstructor(new Type[0] ).Invoke(new object[0]);
    foreach (DictionaryEntry entry in xmlRpcStruct)
    {
        XmlRpcStruct entryStruct = (XmlRpcStruct)entry.Value;
        foreach (DictionaryEntry subEntry in entryStruct)
        {
            if (subEntry.Value.GetType() != typeof(XmlRpcStruct))
            {
                var prop = map.GetType().GetField(subEntry.Key.ToString());
                prop.SetValue(map, subEntry.Value);
            }
            else
            {
                var prop = map.GetType().GetField(subEntry.Key.ToString());
                prop.SetValue(map, MapStructInternal(map.GetType(),(XmlRpcStruct)subEntry.Value));
            }
        }
    }
    return map;
}    

【讨论】:

    【解决方案2】:

    通过反射,您可以在运行时创建一个通用的(以及该类的一个对象),但是,我不相信您可以创建一个通用的方法 .所以,如果你改变你的代码

     public static T MapStruct<T>(XmlRpcStruct xmlRpcStruct) where T : new()  {...}
    

     static class Mapper<T> where T : new() 
     {
          public T MapStruct(XmlRpcStruct xmlRpcStruct) {....}
     }
    
      var mapper = new Mapper<OrderDetails>();
      OrderDetails readyOrder = mapper.MapStruct<OrderDetails>(order);  
    

    那么你应该可以让它工作。

    【讨论】:

    • MethodInfo 确实有一个 MakeGenericMethod 方法可以解决问题,如果提供了该方法,在本例中是 MethodInfo.GetCurrentMethod。生成的 MethodInfo 将被动态调用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    • 2011-09-23
    • 2023-03-07
    • 2014-11-30
    相关资源
    最近更新 更多