【问题标题】:How to call generic extension method for dynamically created type in c#如何在c#中为动态创建的类型调用泛型扩展方法
【发布时间】:2017-01-18 04:23:25
【问题描述】:

我写的扩展如下:

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 的类型是由反射 TypeBuilder 创建的。这意味着代码中的Sample没有明确的类型。

所以,我想找到一些方法来转换泛型 IEnumerable&lt;...&gt; 或调用 Traverse 的扩展方法。

提前致谢。

【问题讨论】:

  • 你有什么问题?

标签: c# generics extension-methods


【解决方案1】:

您的 ObservableTestCollection&lt;T&gt; 必须实现类型 IEnumerable&lt;T&gt; 或派生自具有该实现的类型才能使用您的扩展方法,如下所示:

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 的类型是由反射 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"));

【讨论】:

  • 我对我写的问题进行了一些更新,以更好地表达我现在面临的问题。能不能详细点。谢谢
  • 感谢@CodingYoshi。我对 var ct = Convert.ChangeType(s.GetProperty("Children").GetValue(s), pi.PropertyType) as IEnumerable; 做了一点改动
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多