【问题标题】:How to trigger a Generic Class method recursively changing the type of T?如何以递归方式触发泛型类方法更改 T 的类型?
【发布时间】:2014-06-20 17:38:07
【问题描述】:

我创建了一个通用类来将一些数据解析到类的另一个实例中 (MyClass1)。由于 MyClass1 只有内置的 C# 类型,我的 GenericMethod 工作正常。当MyClass1 有另一个MyClass2 属性并且我仍然想调用我的GenericMethod 来解析我的数据时,问题开始增长。

我无法在其范围内触发我的 Generic Class 方法,因为我需要更改 T 的类型。有没有办法解决这个问题?

public class MyClass1 
{
    public int MyIntProperty { get; set; }
    public string MyStringProperty { get; set; }

    public MyClass2 MyClass2Property { get; set; }
}

public class MyClass2 
{
    public int MyOtherIntProperty { get; set; }
    public string MyOtherStringProperty { get; set; }
    public bool MyOtherBoolProperty { get; set; }
}

public class MyGenericClass<T> where T : class
{
    public static T MyGenericMethod()
    {
        T o = (T)Activator.CreateInstance(typeof(T));
        PropertyInfo[] pi = typeof(T).GetProperties();

        for(int i = 0; i < pi.Count(); i++) 
        {
            if(pi[i].Name == "MyClass2Property") 
            {
                //How to proceed ?
                MyGenericClass<???>.MyGenericMethod(); 
            }
            else 
            {
                pi[i].SetValue(o, Convert.ChangeType(someValue, pi[i].PropertyType), null);
            }
        }
    }
}        

public static void Main(string[] args) 
{
    MyClass1 mc1 = MyGenericClass<MyClass1>.MyGenericMethod();
    //Do something with mc1
}

【问题讨论】:

  • 你不能把MyGenericClass&lt;T&gt;改成MyGenericClass&lt;T,U&gt;然后打电话给MyGenericClass&lt;U&gt;.MyGenericMethod()吗? (如果您添加另一个级别的递归,这当然不会工作......)
  • MyGenericClass 有更多功能吗?想知道为什么类不只是 static 和方法本身的 T 类型参数,比如 MyGenericMethod&lt;T&gt;()
  • 为什么不直接使用 BinaryFormatter 类并序列化 MyClass1? msdn.microsoft.com/en-us/library/…

标签: c# asp.net generics system.reflection


【解决方案1】:

你可以看this post

也许可以尝试这样的事情

public static class MyGenericClass<T> where T : class
{
    public static T MyGenericMethod()
    {
    T o = (T)Activator.CreateInstance(typeof(T));
    PropertyInfo[] pi = typeof(T).GetProperties();

    for(int i = 0; i < pi.Count(); i++) 
    {
        if(pi[i].Name == "MyClass2Property") 
        {
            //How to proceed ?
            Type t = typeof (MyGenericClass<>);
            Type genericType = t.MakeGenericType(new System.Type[] { pi[i].PropertyType });
            var c = Activator.CreateInstance(genericType);
            dynamic mgm = Convert.ChangeType(c, genericType);
            mgm.MyGenericMethod(); 
        }
        else 
        {
            pi[i].SetValue(o, Convert.ChangeType(someValue, pi[i].PropertyType), null);
        }
    }
}

【讨论】:

  • 而且,如果您不想根据属性名称进行切换(因为这会变得非常冗长和乏味),您可以使用自定义属性来装饰您想要区别对待的属性。
  • 根据要求,您甚至不需要装饰属性。你可以有办法测试simple vs complex types
  • 不错的链接,这是一个有用的小扩展。
【解决方案2】:

根据您的需要,您还可以定义一些有关该属性的附加元信息,表明您希望在找到该属性后如何处理。

在其他人的 cmets 和答案的基础上,我想出了一个包含属性修饰的方法,它允许您动态构建对象并具有以下增强功能:

  • 属性可以任意命名
  • 无需添加 if 语句作为新属性。
  • 无需更改MyGenericMethod 方法。
  • 可以将其他元信息添加到自定义属性中,以便在将来添加进一步的自定义。
  • 对象可以嵌套任意深度。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Dynamic;

public class MyClass1 {

    public int MyIntProperty { get; set; }
    public string MyStringProperty { get; set; }

    [MyCustom()]
    public MyClass2 MyClass2Property { get; set; }
}

public class MyClass2 {

    public int MyOtherIntProperty { get; set; }
    public string MyOtherStringProperty { get { return "oooh, fancy"; } set {} }
    public bool MyOtherBoolProperty { get; set; }

}

public static class MyGenericClass<T> where T : class {

    public static T MyGenericMethod() {
        T o = (T)Activator.CreateInstance(typeof(T));
        PropertyInfo[] pi = typeof(T).GetProperties();

        for (int i = 0; i < pi.Count(); i++) {
            if (pi[i].GetCustomAttributes(true).Any() && pi[i].GetCustomAttributes(true).Where((x) => x is MyCustomAttribute).Any()) {
                //How to proceed ?
                var c = Activator.CreateInstance(pi[i].PropertyType);
                Type t = typeof(MyGenericClass<>);
                Type genericType = t.MakeGenericType(new System.Type[] { pi[i].PropertyType });
                MethodInfo m = genericType.GetMethod(MethodInfo.GetCurrentMethod().Name);
                c = m.Invoke(null, null);
                pi[i].SetValue(o, c, null);
            } else {
                //Normal property assignment.
            }
        }
        return o;
    }
}

public class Program {

    public static void Main(string[] args) {
        MyClass1 mc1 = MyGenericClass<MyClass1>.MyGenericMethod();
        //Do something with mc1
        Console.WriteLine(mc1.MyClass2Property.MyOtherStringProperty);
        Console.ReadLine();
    }

}

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false)]
public class MyCustomAttribute : Attribute {

}

我对此进行了调整,使其可以按原样运行。

编辑:

我还更改了代码以调用自身调用的方法以避免“魔术字符串”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-28
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    相关资源
    最近更新 更多