如何重载/替换/扩展通用代码中使用的C#接口

如何重载/替换/扩展通用代码中使用的C#接口,c#,interface,C#,Interface,我先给你讲一点背景知识 我的公司为我们的应用程序(windows服务)选择了一种设计方法,通过核心公共代码的集中(内部nuget repo),允许更多的代码重用。这使得到目前为止维护测试和构建新服务变得更加容易 基本上,所有服务都使用SqlDependency从数据库获得工作可供处理的通知。当SqlDependency对象收到通知时,它调用以下命令 public interface IRequestReceiver : IDisposable { IEnumerable<IRequ

我先给你讲一点背景知识

我的公司为我们的应用程序(windows服务)选择了一种设计方法,通过核心公共代码的集中(内部nuget repo),允许更多的代码重用。这使得到目前为止维护测试和构建新服务变得更加容易

基本上,所有服务都使用SqlDependency从数据库获得工作可供处理的通知。当SqlDependency对象收到通知时,它调用以下命令

public interface IRequestReceiver : IDisposable
{
    IEnumerable<IRequest> GetRequests(int maxRequestNumber);
}
新的

正如您所看到的,它只是一些附加属性,但我不想开始在现有的IRequest接口中引入这些属性


谢谢你

创建一个V2接口,它要么源于初始版本,要么完全独立于初始版本(需要做更多的工作)。然后在需要的地方使用V2:检查请求是否为V2,强制转换对象,然后调用V2属性


这可能需要相当多的工作才能在您需要的任何地方启用V2属性。如果这不可能,您可以选择让两个独立的系统保持活动状态,并排运行。

想想开闭原则

您的IRequest已投入生产。您的客户机也已经在生产中使用IRequest

您关心的是希望使用新功能的新客户机(或旧客户机)

简而言之。 1.不要在IRequest中更改任何内容 2.改为使用IRequest扩展,例如:

public interface IRequestExtensions
{
    int NotificationId { get; set; }

    int StatusId { get; set; }

    string StatusCode { get; set; }

    string StatusMessage { get; set; }

    string Destination { get; set; }

    string BusinessProcessCode { get; set; }

    string MsgType { get; set; }

    string MessageId { get; set; }
}
然而,我看到的是,在新的IRequest中,您有向后不兼容的类型。对于这个解释(因为您没有提到不兼容的类型),我没有将它们包括在IRequestExtensions中

然后,您可以连接您的系统,并提供一个新的界面,如IRequestNew,它将包括旧的和新的东西

public interface IRequestNew : IRequest, IRequestExtensions
{
}
现在,新的(和旧的现有)客户机应该使用IRequestNew(只是一个名称,不漂亮,但你知道),而对于想要实现新接口的旧客户机,只需在其类中添加一个额外的IRequestExtension


您如何迁移每个人以使用IRequest作为所有功能的真正新名称。那又是另一回事了

另一种解决方法是对
GetRequests

IEnumerable<T> GetRequests<T>(int maxRequestNumber);
IEnumerable GetRequests(int-maxRequestNumber);
但是调用GetRequest的类应该知道它们所期望的类型。 如果他们期望IRequestOld/IRequestNew,那么应该在调用GetRequests时传递它

IRequestOld request = GetRequest<RequestOld>(maxRequestNumber);
IRequestNew request = GetRequest<RequestNew>(maxRequestNumber);
IRequestOld请求=GetRequest(maxRequestNumber);
IRequestNew request=GetRequest(maxRequestNumber);
示例程序

class Program
{

    public static void Main()
    {
        Number n = new Number();
        IOne one = n.GetNumberObject<One>();
        one.PrintOne();
        ITwo two = n.GetNumberObject<Two>();
        two.PrintTwo();
    }

    public interface INumbers
    {
        T GetNumberObject<T>() where T : new();
    }
    public class Number : INumbers
    {
        public T GetNumberObject<T>() where T : new()
        {
            return new T();
        }
    }

    public interface IOne
    {
        void PrintOne();
    }
    public interface ITwo
    {
        void PrintTwo();
    }

    class One : IOne
    {
        public void PrintOne()
        {
            Console.WriteLine("One");
        }
    }
    class Two : ITwo
    {
        public void PrintTwo()
        {
            Console.WriteLine("Two");
        }
    }
}
类程序
{
公共静态void Main()
{
编号n=新编号();
IOne=n.GetNumberObject();
1.PrintOne();
ITwo two=n.GetNumberObject();
二、打印二();
}
公共接口单位
{
T GetNumberObject(),其中T:new();
}
公共类编号:INumbers
{
公共T GetNumberObject(),其中T:new()
{
返回新的T();
}
}
公共接口
{
void PrintOne();
}
公共接口ITwo
{
void printwo();
}
第一类:伊奥尼
{
公共无效PrintOne()
{
控制台。写入线(“一”);
}
}
第二类:ITwo
{
第二号公共图书馆()
{
控制台。写入线(“两”);
}
}
}

新建界面,并将其用于需要新特性的零件。欲了解更多信息,请阅读此处:sr28我不确定这是否适用,因为扩展是方法??然而,我特别关注我想要扩展的属性。谢谢你能详细介绍一下吗?我该如何解决V1中有V2不需要或不知道如何创建的项(如IRequestDetail)的问题?感谢您可能需要将所有公共属性放在通用接口中。然后在V1和V2接口中从中派生。好的,所以选项2(并排运行两个服务)不是运行程序(时间表和预算)。。至于选项1,我可以在nuget中创建这个接口的新版本并部署它,然后在旧版本上保留现有服务,直到我有时间将它们重构成一个泛型,在ithad下面有一个v1和v2接口,以选择将所有公共属性放在泛型接口中并从中继承。谢谢你的快速回复
IRequestOld request = GetRequest<RequestOld>(maxRequestNumber);
IRequestNew request = GetRequest<RequestNew>(maxRequestNumber);
class Program
{

    public static void Main()
    {
        Number n = new Number();
        IOne one = n.GetNumberObject<One>();
        one.PrintOne();
        ITwo two = n.GetNumberObject<Two>();
        two.PrintTwo();
    }

    public interface INumbers
    {
        T GetNumberObject<T>() where T : new();
    }
    public class Number : INumbers
    {
        public T GetNumberObject<T>() where T : new()
        {
            return new T();
        }
    }

    public interface IOne
    {
        void PrintOne();
    }
    public interface ITwo
    {
        void PrintTwo();
    }

    class One : IOne
    {
        public void PrintOne()
        {
            Console.WriteLine("One");
        }
    }
    class Two : ITwo
    {
        public void PrintTwo()
        {
            Console.WriteLine("Two");
        }
    }
}