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

时间:2017-06-27 12:15:58

标签: c# generics interface

我知道有类似的问题,但我没有发现任何与我所做的相似的事情。

假设我有这个:

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
    }
}

并且,由于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();
}

虽然这很好用,但感觉就像黑客一样,因为我必须记住JobA需要一个不被界面强制执行的setter。
我最初使用的是双IJob界面(IJobIJob<T>)但这意味着我必须从IJob<T>投射到IJob并且我没有'那样的。
有没有更清洁的方法呢?

2 个答案:

答案 0 :(得分:2)

更新

我最初的建议是创建一个抽象类,在构造函数中设置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();
}

强制派生类设置JobData属性。

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

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

原始答案

遵循抽象基类的想法,考虑一个抽象的工厂方法,它会强制任何派生类在属性本身中提供数据

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

    public abstract void Run();

    public abstract T GetData();
}

或拥有私有的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();
}

任何派生的实现都将被强制实现GetData方法。

答案 1 :(得分:1)

据我所知,您希望在继承上强制执行setter定义,这也将具有可访问性限制!如果您定义了一个setter方法,您仍然可以将其公开访问。并且,“双IJob界面(IJobIJob<T>)但这意味着我必须从IJob<T>投射到IJob”听起来不太好给你。

对于这种情况没有太多解决方案,但可以使用抽象类来解决一个问题。我在这里建议的是这样的:

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
    }
}

现在,您没有对后续类实现IJob,而是扩展Abs_JobA抽象类。