简体   繁体   English

带有通用接口参数的通用接口列表

[英]List of generic interface with generic interface parameter

I know similar questions have been asked, but I didn't find any which was similar enough to what I did. 我知道有类似的问题,但我没有发现任何与我所做的相似的问题。

Let's say I have this: 假设我有这个:

public interface IData
{
    string Data { get; set; }
}
public interface IJob<out T> where T: IData
{
    T JobData { get; } // works because no setter

    void Run();
}

public class JobAData : IData
{
    public string Data { get; set; }
}

public class JobA : IJob<JobAData>
{
    public JobAData JobData { get; private set; } // implements IJob's get plus a set

    public JobA(JobAData data)
    {
        JobData = data;
    }

    public void Run()
    {
        //can use JobData nicely here
    }
}

And, because of the out parameter, this also works: 并且,由于out参数,这也有效:

List<IJob<IData>> jobs = new List<IJob<IData>>();
jobs.Add(new JobA(new JobAData()));

//in another class, extremely simplified (actually running with Quartz)
foreach (var job in jobs)
{
    job.Run();
}

While this works fine, it feels like a hack since I have to remember that JobA needs a setter that is not enforced by the interface. 虽然这很好用,但感觉就像是一个黑客,因为我必须记住, JobA需要一个不受界面强制执行的setter。
I originally was using a double IJob interface (an IJob and an IJob<T> ) but that meant I had to cast from IJob<T> to IJob and I didn't like that. 我最初使用的是一个双IJob接口(一个IJob和一个IJob<T> ),但这意味着我必须从IJob<T>IJob ,我不喜欢这样。
Is there any cleaner way to do this? 有没有更清洁的方法来做到这一点?

UPDATE UPDATE

My original suggestion was to create an abstract class that sets the Data in the constructor, 我最初的建议是创建一个抽象类,在构造函数中设置Data,

public abstract class JobBase<T> : IJob<T> where T : IData {

    public JobBase(T data) {
        JobData = data;
    }

    public T JobData { get; private set; }

    public abstract void Run();
}

forcing derived classes to set the JobData property. 强制派生类设置JobData属性。

public class JobA : JobBase<JobAData> {
    public JobA(JobAData data) : base(data) { }

    public void Run() {
        //can use JobData nicely here
    }
}

ORIGINAL ANSWER 原始答案

Following the abstract base class idea consider a abstract factory method that would force any derived class to provide data, either in the property itself 遵循抽象基类的想法,考虑一个抽象的工厂方法,它会强制任何派生类在属性本身中提供数据

public abstract class JobBase<T> : IJob<T> where T : IData {
    public T JobData { get { return GetData(); } }

    public abstract void Run();

    public abstract T GetData();
}

or having a private setter and setting it one time in the constructor 或者有一个私有的setter并在构造函数中设置它一次

public abstract class JobBase<T> : IJob<T> where T : IData {

    public JobBase() {
        JobData = GetData();
    }

    public T JobData { get; private set; }

    public abstract void Run();

    public abstract T GetData();
}

Any derived implementations would be forced to implement the GetData method. 任何派生的实现都将被强制实现GetData方法。

From what I understand, you want to enforce setter definition on inheritance which would have accessibility restriction as well! 根据我的理解,您希望在继承上强制执行setter定义,这也将具有可访问性限制! If you define a setter method, you would still end up making it publicly accessible. 如果您定义了一个setter方法,您仍然可以将其公开访问。 And, "double IJob interface (an IJob and an IJob<T> ) but that meant I had to cast from IJob<T> to IJob " doesn't sound good to you. 并且,“双IJob接口(一个IJob和一个IJob<T> )但这意味着我必须从IJob<T>IJob ”对你来说听起来不太好。

There are not much solutions to this situation but one work around can be restriction using Abstract Classes. 对于这种情况没有太多解决方案,但可以使用抽象类来解决一个问题。 What I am suggesting here is something like this: 我在这里建议的是这样的:

public interface IData
{
    string Data { get; set; }
}
public interface IJob<out T> where T : IData
{
    T JobData { get; }

    void Run();
}

public class JobAData : IData
{
    public string Data { get; set; }
}

public abstract class Abs_JobA : IJob<JobAData>
{
    public abstract JobAData JobData { get; protected set; }
    public abstract void Run();
}

public class JobA : Abs_JobA
{
    public override JobAData JobData
    {
        get;
        protected set;
    }

    public JobA(JobAData data)
    {
        this.JobData = data;
    }

    public override void Run()
    {
        //can use JobData nicely here
    }
}

So now, you do not implement IJob to subsequent classes but, rather you extend Abs_JobA abstract class. 所以现在,你没有将IJob实现到后续类,而是扩展了Abs_JobA抽象类。

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

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