如何使用反射来传递" MyTypes"一个约束为T:MyType的泛型方法?

时间:2013-11-11 16:25:13

标签: c# generics reflection

如何使用反射将每个“MyTypes”列表传递给约束为T:MyDataObject的泛型方法?

public interface IAllMyTypes
{
    List<FirstType> MyType1 { get; set; }
    List<SecondType> MyType2 { get; set; }
    List<ThirdType> MyType3 { get; set; }
}

FirstType,SecondType和ThirdType继承自MyDataObject(如下所示),但具有不同的属性。

public class FirstType : MyDataObject
{
  //various properties
}   

我无法将数据传递给具有此签名的方法:

void DoSomething<T>(IEnumerable<T> enumerable) where T : MyDataObject;

错误是“无法推断出类型参数。”

这是我不成功的尝试:

public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
    foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
    {
        var x = propertyInfo.GetValue(allMyTypes) as IList;//im not sure what to do here
        if(x==null) throw new Exception("still wrong");

        DoSomething(x);
    }
}   

如果直接提供属性,DoSomething(..)中的所有代码都能正常工作:

public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
    DoSomething(allMyTypes.MyType1);
    DoSomething(allMyTypes.MyType2);
    DoSomething(allMyTypes.MyType3);
}

3 个答案:

答案 0 :(得分:2)

如果要使用反射,也可以使用反射调用辅助方法:

您必须获取MethodInfo泛型方法并创建一个通用方法反射句柄,以实际Invoke该方法。在这种情况下,需要在运行时获取泛型方法的类型T

public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
    var method = this.GetType().GetMethod("DoSomething", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
    foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
    {
        var x = propertyInfo.GetValue(allMyTypes, null);
        if(x==null) throw new Exception("still wrong");

        // obtain the type from the property - other techniques can be used here.
        var genericMethod = method.MakeGenericMethod(new[] {propertyInfo.PropertyType.GetGenericArguments()[0]})
        //execute the generic helper
        genericMethod.Invoke(this, new[]{x});
    }
} 

public void DoSomething<T>(IList<T> list) where T : MyDataObject {

}

答案 1 :(得分:0)

我很难找到一个案例,你需要按照自己的方式构建数据,而不会过度复杂化。如果您找到了合法的案例,请发表评论,我会更新我的答案,以反映您的需求。

您可以从基类开始,将其抽象化并在其中添加抽象方法DoSomething

public abstract class MyDataObject{
  public string SomeSharedProperty{get;set;}
  protected abstract DoSomething(); 
}

public class FirstType: MyDataObject{ 
  protected override DoSomething(){
    Console.WriteLine(SomeSharedProperty);
  }
}


public class Consumer{
  public void DoSomethingWithAllMyTypes(List<MyDataObject> source)
  {
    source.ForEach(x=>x.DoSomething());
  }
}

答案 2 :(得分:0)

您可以使用Linq方法调用Cast<T>将列表转换为正确的类型

public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
    foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
    {
        var x = propertyInfo.GetValue(allMyTypes) as IEnumerable
        if(x==null) throw new Exception("still wrong");

        DoSomething(x.Cast<MyDataObject>());
    }
}