在运行时使用通用接口创建通用类型

Bob*_*orn 5 .net c# linq generics expression-trees

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

这是基类:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity
Run Code Online (Sandbox Code Playgroud)

这是界面:

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

这就是我使用它的方式:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

我从上面坚持这条线:

var ravenWriter = Activator.CreateInstance(ravenWriterType);
Run Code Online (Sandbox Code Playgroud)

这是我的问题:
如何将其用作RavenWriterBase或IRavenWriter?就像是:

ravenWriter.Initialize(60, func);
Run Code Online (Sandbox Code Playgroud)

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

var ravenWriter = Activator.CreateInstance(ravenWriterType) as IRavenWriter<>;
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

但现在我需要能够以通用的方式使用它.我怎样才能做到这一点?

更新:

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

dynamic ravenWriter = Activator.CreateInstance(ravenWriterType);
ravenWriter.Initialize(60);
Run Code Online (Sandbox Code Playgroud)

我作弊了一点,因为我意识到每个IDataEntity的Func是相同的,所以没有必要作为参数传递给Initialize().但是,至少现在我可以调用Initialize().但是现在Func是相同的,我也不需要通用接口.

Ali*_*tad 2

我的解决方案是:

  • 创建一个非通用接口IRavenWriter
  • 使IRavenWriter<T>继承自IRavenWriter
  • 保留ExecuteExecutionIntervalInSeconds进入IRavenWriter
  • 在你的作家中拥有并使用IRavenWriterFunc<DateTime>
  • 搬去InitializeIRavenWriter<T>
  • 使用工厂根据类型和表达式初始化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);
}
Run Code Online (Sandbox Code Playgroud)

你使用:

GetFunk<MyDateTime>(x => x.This, new MyDateTime(){This = DateTime.Now});
Run Code Online (Sandbox Code Playgroud)