简体   繁体   English

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

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

The extension I wrote is as follows: 我写的扩展名如下:

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

The class Sample shown below is created dynamically using Reflection TypeBuilder. 下面显示的类Sample是使用Reflection TypeBuilder动态创建的。 The object instanced that I created run time is like: 我创建的运行时实例化的对象类似于:

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 above is derived by ObservableCollection 上面的ObservableTestCollection由ObservableCollection派生

typeBuilder here below is built by Reflection TypeBuilder. 下面的typeBuilder由Reflection TypeBuilder构建。 What I like to do is : 我喜欢做的是:

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

The problem here is that I can not cast to IEnumerable, since the Type for Sample is the one created by reflection TypeBuilder. 这里的问题是我无法转换为IEnumerable,因为Sample的类型是反射TypeBuilder创建的类型。 It means that there is no clear type for Sample in code. 这意味着代码中没有明确的Sample类型。

So, I want to find out some way to cast generic IEnumerable<...> or invoke extension method of Traverse. 因此,我想找出一种方法来转换通用IEnumerable<...>或调用Traverse的扩展方法。

Thanks in advance. 提前致谢。

Your ObservableTestCollection<T> has to implement type IEnumerable<T> or derive from a type which has that implementation to be able to use your extension method like this: 您的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();
    }
}

Then you can reflect on it like this: 然后您可以像这样思考它:

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

I am using object for T but you can use whatever you need. 我正在为T使用object ,但是您可以使用任何需要的对象。 Also, you would need to add some items to the Children property at runtime so you can traverse them using your extension-but I assume you know this. 另外,您需要在运行时将一些项目添加到Children属性,以便可以使用扩展名遍历它们-但我想您知道这一点。

EDIT 编辑

You edited your question and added this: 您编辑了问题并添加了以下内容:

The problem here is that I can not cast to IEnumerable, since the Type for Sample is the one created by reflection TypeBuilder. 这里的问题是我无法转换为IEnumerable,因为Sample的类型是反射TypeBuilder创建的类型。 It means that there is no clear type for Sample in code. 这意味着代码中没有明确的Sample类型。

Does not matter, it will still work. 没关系,它仍然可以工作。 Here is some code where I do not even mention Sample as a class but as a type created on the fly: 这是一些代码,在这里我什至没有提到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"));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM