【问题标题】:Create Generic Type with Generic Interface at Run Time在运行时使用泛型接口创建泛型类型
【发布时间】:2012-04-13 15:36:31
【问题描述】:

我已经解决了几个小时的问题,我想我已经接近了。我正在开发一个应用程序,我们可以有 50-100 种以相同方式执行的类型。因此,我没有创建 50-100 个类,而是尝试使其具有通用性,这就是我所拥有的:

这是基类:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity

这是界面:

public interface IRavenWriter<T>
{
    int ExecutionIntervalInSeconds { get; }
    void Execute(object stateInfo);
    void Initialize(int executionIntervalInSeconds, Expression<Func<T, DateTime>> timeOrderByFunc);
}

这就是我使用它的方式:

private static void StartWriters()
{
    Assembly assembly = typeof(IDataEntity).Assembly;
    List<IDataEntity> dataEntities = ReflectionUtility.GetObjectsForAnInterface<IDataEntity>(assembly);

    foreach (IDataEntity dataEntity in dataEntities)
    {
        Type dataEntityType = dataEntity.GetType();
        Type ravenWriterType = typeof(RavenWriterBase<>).MakeGenericType(dataEntityType);

        Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime;

        // This is where I'm stuck. How do I activate this as RavenWriterBase<T>?
        var ravenWriter = Activator.CreateInstance(ravenWriterType);

        //ravenWriter.Initialize(60, func);  // I can't do this until I cast.

        // More functionality here (not part of this issue)
    }
}

我从上面卡在这条线上:

var ravenWriter = Activator.CreateInstance(ravenWriterType);

这是我的问题:
如何将它用作 RavenWriterBase 或 IRavenWriter?比如:

ravenWriter.Initialize(60, func);

我认为它需要是这样的,但我需要为 IRavenWriter 指定一个类型,我还不知道:

var ravenWriter = Activator.CreateInstance(ravenWriterType) as IRavenWriter<>;

如果我将鼠标悬停在 ravenWriter 上,我就成功获得了我的对象:

但现在我需要能够以通用方式使用它。我该怎么做?

更新:

我只是想使用动态关键字,这很有效:

dynamic ravenWriter = Activator.CreateInstance(ravenWriterType);
ravenWriter.Initialize(60);

我有点作弊,因为我意识到每个 IDataEntity 的 Func 都是相同的,因此没有必要将其作为参数传递给 Initialize()。但是,至少现在我可以调用 Initialize()。但是既然 Func 是一样的,我也不应该需要泛型接口。

【问题讨论】:

  • 听起来像是对泛型的不当使用。当您发现自己需要基于不同类型运行不同的方法,但类型仅在运行时才知道时,您希望利用多态性。仿制药给你带来了什么?您能否在没有泛型的情况下按原样运行方法,即使用 IDataEntity?
  • 我同意 mellamokb。但是,如果您设置了泛型,为什么不创建一个可以非泛型实例化的包装类。包装器应该有一个方法,该方法根据作为参数传入的类型返回 RavenWriterBase 的实例。然后,实例化包装器并以请求的类型作为参数调用方法。这将需要一个大的 switch 语句,但至少不需要 200 个单独的类。
  • 您是否创建了其他不使用 IDataEntity for T 的表达式?还是 T 始终是 IDataEntity?如果 T 总是 IDataEntity,为什么要使用泛型?
  • @DavidCowden:好主意,实际上并没有那么难,因为使用我们一直使用的 T4 模板可以轻松实现这一点。
  • @mellamokb 我没有根据不同的类型运行不同的方法。我一定没有说清楚。我不明白你在哪里看到的。我想在每个实例上调用 Initialize() 和 Execute()。

标签: c# .net linq generics expression-trees


【解决方案1】:

我的解决办法是:

  • 创建IRavenWriter的非通用接口
  • 使IRavenWriter&lt;T&gt; 继承自IRavenWriter
  • 将Execute 和ExecutionIntervalInSeconds 保留在IRavenWriter 中
  • 让IRavenWriter 拥有Func&lt;DateTime&gt; 并在你的作家中使用它
  • 将Initialize 移动到IRavenWriter&lt;T&gt;
  • 使用工厂根据类型和表达式初始化Func:

例如:

public class MyDateTime
{
    public DateTime This { get; set; }
}

public static Func<DateTime> GetFunk<T>(Expression<Func<T, DateTime>> timeOrderByFunc, T t)
{
    return () => timeOrderByFunc.Compile()(t);
}

而你使用:

GetFunk<MyDateTime>(x => x.This, new MyDateTime(){This = DateTime.Now});

【讨论】:

  • 我不确定我是否遵循。这如何让我将 ravenWriter 用作 RavenWriterBase 或 IRavenWriter?
  • @BobHorn 它没有。您无法在其中了解RavenWriterBase&lt;&gt;。相反,您需要在其中使用IRavenWriterBase(非通用)。那里不存在该类型的编译时知识,因此您无法强制转换。
  • 谢谢。我刚刚编辑了我的问题,以展示如何使用动态调用 Initialize()。我认为这应该可行。
  • @BobHorn dynamic 关键字并不能真正解决问题。您的类型层次结构仍然混乱,但您没有处理它,而是忽略了类型系统。恕我直言,这不是真正的解决方案。
【解决方案2】:

将运行时Type 转换为编译时通用类型参数并不难。只需引入用于创建/初始化对象的新接口:

interface IRawenWriterFactory { object Create(); } class RawenWriterFactory<T> : IRawenWriterFactory { public object Create() { Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime; var ravenWriter = new RavenWriterBase<T>(); ravenWriter.Initialize(60, func); return ravenWriter; } }

现在只需使用 dataEntityType 创建 RawenWriterFactory,就像您创建 ravenWriter 一样,并通过非通用 IRavenWriterFactory 接口使用它。

但是,如果您要更改设计,可能会有更简单的解决方案。例如。如果您将 Initialize 方法转换为构造函数,您将能够将 func 作为 Activator.CreateInstance 参数传递,并且您根本不需要使用通用接口进行初始化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-21
    • 1970-01-01
    相关资源
    最近更新 更多