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

How to call generic extension method for dynamically created type in c#

我写的扩展如下:

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

下面显示的 class 示例是使用 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 的 Type 是由反射 TypeBuilder 创建的。这意味着代码中没有明确的Sample类型。

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

提前致谢。

您的 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 属性 添加一些项目,以便您可以使用 extension-but 遍历它们我假设您知道这一点。

编辑

你编辑了你的问题并添加了这个:

The problem here is that I can not cast to IEnumerable, since the Type for Sample is the one created by reflection TypeBuilder. It means that there is no clear type for Sample in code.

没关系,它仍然有效。这是一些代码,其中我什至没有提到 Sample 作为 class 而是作为动态创建的类型:

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"));