如何在c#中为动态创建的类型调用泛型扩展方法

时间:2017-01-18 04:23:25

标签: c# generics extension-methods

我写的扩展如下:

public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, bool> predicate) where T : class,  new()
{
    ....
}

下面显示的类Sample是使用Reflection TypeBuilder动态创建的。 我创建运行时的对象实例就像:

public class Sample
{
    public Sample()
    {
        Children= new ObservableTestCollection<Sample>(this);
    }

    public Sample(IEnumerable<Sample> source)
    {
        Children= new ObservableTestCollection<Sample>(this, source);
    }

    public ObservableTestCollection<Sample> Children;
}

上面的ObservableTestCollection由ObservableCollection

派生 下面的

typeBuilder是由Reflection TypeBuilder构建的。 我喜欢做的是:

var type = typeBuilder.CreateType();
var obj = Activator.CreateInstance(type);
var results = (IEnumerable<...>)(obj.GetProperty("Children").GetValue(obj)).Traverse(s=>s!=null);

这里的问题是我无法转换为IEnumerable,因为Sample for Sample是由反射TypeBuilder创建的。这意味着代码中的Sample没有明确的类型。

所以,我想找出一些方法来转换泛型IEnumerable<...>或调用Traverse的扩展方法。

提前致谢。

1 个答案:

答案 0 :(得分:2)

您的ObservableTestCollection<T>必须实现类型IEnumerable<T>,或者从具有该实现的类型派生才能使用您的扩展方法,如下所示:

public class ObservableTestCollection<T> : IEnumerable<T>
{
    private Sample sample;
    private IEnumerable<Sample> source;

    public ObservableTestCollection(Sample sample)
    {
        this.sample = sample;
    }

    public ObservableTestCollection(Sample sample, IEnumerable<Sample> source)
    {
        this.sample = sample;
        this.source = source;
    }

    public IEnumerator<T> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

然后你可以像这样反思:

var obj = Activator.CreateInstance(typeof(Sample));
var pi = obj.GetType().GetProperty("Children");
var ct = Convert.ChangeType(obj, pi.PropertyType) as ObservableTestCollection<Sample>;
var results = (IEnumerable <Sample>)(ct as IEnumerable<object>).Traverse(s => s.Equals("1"));

我正在object使用T但您可以使用您需要的任何内容。此外,您需要在运行时向Children属性添加一些项目,以便您可以使用扩展程序遍历它们 - 但我认为您知道这一点。

修改

您修改了问题并添加了此内容:

  

这里的问题是我无法转换为IEnumerable,因为Sample for Sample是由反射TypeBuilder创建的。这意味着代码中的Sample没有明确的类型。

无关紧要,它仍然有效。这里有一些代码,我甚至没有提到Sample作为类,而是作为动态创建的类型:

AssemblyName assemblyName
= new AssemblyName("MyDynamicAssembly");
AssemblyBuilder assemblyBuilder
    = AppDomain.CurrentDomain.DefineDynamicAssembly(
        assemblyName,
        AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder
    = assemblyBuilder.DefineDynamicModule("MyDynamicModule");
TypeBuilder typeBuilder
    = moduleBuilder.DefineType("Sample");
var obj = Activator.CreateInstance(typeBuilder.CreateType());
var pi = obj.GetType().GetProperty("Children");
var ct = Convert.ChangeType(obj, pi.PropertyType) as IEnumerable<object>;
var results = (ct as IEnumerable<object>).Traverse(s => s.Equals("1"));