如何以递归方式更改T的类型来触发Generic Class方法?

时间:2014-06-20 17:38:08

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

我创建了一个通用类来将一些数据解析为另一个类的实例(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
}

2 个答案:

答案 0 :(得分:5)

您可以查看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);
        }
    }
}

答案 1 :(得分:1)

根据您的需要,您还可以定义一些有关该属性的其他元信息,指明如果找到您想要对其执行的操作。

以他人为基础&#39;评论和答案,这是我想出的内容,包括允许您动态构建对象的属性修饰,并具有以下增强功能:

  • 可以将您想要的任何名称命名为
  • 无需添加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 {

}

我调整了它,因此可以按原样运行。

修改

我还更改了代码以调用自身被调用的方法以避免使用&#34;魔术字符串&#34;。