简体   繁体   English

通用类型,接口

[英]Generic types, Interfaces

I would like to create a generic notification engine. 我想创建一个通用的通知引擎。 The idea is to have a single core engine to process any type of notification. 这个想法是有一个单一的核心引擎来处理任何类型的通知。 This engine will process notification and handle all logging, error handling etc.. 该引擎将处理通知并处理所有日志记录,错误处理等。

I created 3 simple interfaces: 我创建了3个简单的界面:

public interface INotificationInput
{
    /// <summary>
    /// Friendly Name for logging/tracing usage
    /// </summary>
    string FriendlyName { get; set; }

    string NotificationCode{ get; set; }

    Double Version { get; set; } 
}

public  interface INotificationOutput
{
    /// <summary>
    /// Friendly Name for logging/tracing usage
    /// </summary>
    string FriendlyName { get; }
}

public interface INotificationProvider<out Toutput, Tinput> where Toutput : INotificationOutput where Tinput : INotificationInput
{
    /// <summary>
    /// Friendly Name for logging/tracing usage
    /// </summary>
    string FriendlyName { get; set; }

    /// <summary>
    /// Generates and returns an INotificationOutput from data
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    Toutput GenerateNotificationOutput(Tinput data);
}

So the INotificationProvider will chunk the INotificationInput to create a INotificationOutput. 因此,INotificationProvider将对INotificationInput进行分块以创建INotificationOutput。

That could be information to send a email, a sms, you name it, the engine will call the methods and do the magic of scheduling, logging, handling errors and so on.. 那可能是发送电子邮件的信息,一条短信(您将其命名),引擎将调用这些方法并发挥调度,记录日志,处理错误等作用。

I implemented the interface like this: 我实现了这样的接口:

/// <summary>
    /// INotificationInput represented by a dummy object
    /// </summary>
    public class DummyNotificationInput : INotificationInput
    {
        public string FriendlyName { get; set; }
        public string NotificationCode { get; set; }
        public double Version { get; set; }
    }

public class DummyNotificationOutput : INotificationOutput
{
    public string FriendlyName { get; private set; }
}

public class DummyProvider : INotificationProvider<DummyNotificationOutput, DummyNotificationInput>
{
    public string FriendlyName { get; set; }

    public DummyNotificationOutput GenerateNotificationOutput(DummyNotificationInput data)
    {
        throw new NotImplementedException();
    }
}

Now I would like my engine to have a list of provider: 现在,我希望我的引擎具有提供程序列表:

 var providersList = new List<INotificationProvider<INotificationOutput, INotificationInput>>();

The problem is that I cannot to the following: 问题是我无法做到以下几点:

providersList.Add(new DummyProvider<DummyNotificationOutput, DummyNotificationInput>());

There must be a solution. 必须有一个解决方案。 Am I using the wrong approach? 我使用错误的方法吗?

The second generic type argument to INotificationProvider isn't covariant (at a conceptual level), but you're trying to use it as if it were. INotificationProvider的第二个泛型类型参数不是协变的(在概念级别上),但是您试图像使用协变一样使用它。 It is actually contravariant. 它实际上是对立的。

In your list of INotificationProvider objects you've defined the input notification as an INotificationInput . INotificationProvider对象列表中,您已将输入通知定义为INotificationInput This means objects added to this list need to be able to accept any type of INotificationInput as input to their GenerateNotificationOutput function . 这意味着添加到此列表的对象需要能够接受任何类型的INotificationInput作为其GenerateNotificationOutput函数的输入 You're trying to add an object that only knows how to handle DummyNotificationInput objects. 您试图添加仅知道如何处理DummyNotificationInput对象的对象。 It would fail if it were passed some other type of input. 如果传递了其他类型的输入,它将失败。

Either your provider needs to accept INotificationInput objects, if you want to be able to add it to that list, or the list needs to define all of the objects as accepting DummyNotificationInput . 如果希望将提供者添加到该列表中,则提供者需要接受INotificationInput对象,或者该列表需要将所有对象都定义为接受DummyNotificationInput

As Servy has already answered, you can't really do this due to what you providersList is expecting 正如Servy已经回答的那样,由于providersList的期望,您无法真正做到这一点

With this in mind, it may actually be simpler to just make INotificationProvider non-generic: 考虑到这一点,仅使INotificationProvider为非泛型实际上可能会更简单:

public interface INotificationProvider
{
    /// <summary>
    /// Friendly Name for logging/tracing usage
    /// </summary>
    string FriendlyName { get; set; }

    /// <summary>
    /// Generates and returns an INotificationOutput from data
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    INotificationOutput GenerateNotificationOutput(INotificationInput data);
}

Then the DummyProvider becomes: 然后, DummyProvider变为:

public class DummyProvider : INotificationProvider
{
    public string FriendlyName { get; set; }

    public INotificationOutput GenerateNotificationOutput(INotificationInput data)
    {
        throw new NotImplementedException();
    }
}

Now, probably not what you had in mind - you are expecting to pass DummyNotificationInput instances to DummyProvider 现在,可能不是您所想的那样-您期望将DummyNotificationInput实例传递给DummyProvider

You could just type check in your Provider code 您只需在您的Provider代码中输入check

public class DummyProvider : INotificationProvider
{
    public string FriendlyName { get; set; }

    public INotificationOutput GenerateNotificationOutput(INotificationInput data)
    {
        if (!(data is DummyNotificationInput)) throw new ArgumentException("Invalid type specified", "data");

        return something...;
    }
}

Obviously, you lose design time checking - but if you really need to put them in a covariant list you can't provide an implementor that has a derived generic type argument 显然,您浪费了设计时间检查-但是,如果您确实需要将它们放在协变量列表中,则无法提供具有派生泛型类型参数的实现程序

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

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