1

我有几个基本的消息枚举,我将它们放入一个界面来控制它们。但是,当我这样做时,我需要支持旧消息,同时仍添加新消息。最好的方法是什么?

这是Msg接口的总体思路:

public interface Msg
{
    /// <summary>
    /// Gets the ID of the message
    /// </summary>
    Legacy_Msgs MessageId { get; }
    //New_Msgs MessageId { get; }    // How implement use this?

    /// <summary>
    /// Converts the message to a byte array representation
    /// </summary>
    byte[] MsgBytes { get; }
}

但是我的问题是,为New_Msgs, 继承Msg和覆盖 的新接口是否MessageId更有意义,或者从效率的角度来看,为枚举提供一个全新NewMsg的接口是否更有意义。 我意识到这两种解决方案都可以工作,但我想知道作为另一个正在研究这种解决方案的开发人员,什么更有意义?New_Msg

4

5 回答 5

2

接口不能覆盖,但您可以通过接口将新项目添加到合同中。

如果行为将在实现之间发生变化,使得它们不向后兼容,那么您应该创建一个与旧接口/实现无关的全新接口/实现,因为有人可以创建新接口/实现的实例,并将其传递给期待旧的消费者。

单个实现可以实现这两个接口以尽可能保持兼容性。如果接口的成员有重叠,那么您可以使用显式接口实现将两个接口一起维护。

于 2012-06-13T14:46:40.243 回答
1

如果其他人正在使用此界面(我认为任何一种解决方案都应该没问题),我建议使用“过时”标签来提醒其他开发人员有关更新的信息。

http://msdn.microsoft.com/en-us/library/22kk2b44(v=vs.80).aspx

public interface INewMsgId : IMsgId
{
}

[System.Obsolete("use interface INewMsgId ")]
public interface ILegacyMsgId : IMsgId
{
{
于 2012-06-13T14:51:56.857 回答
1

这种结构可能会给你更多的灵活性,同时让你的IMsg合同对消费者来说是一致的。

// the following three MsgId contracts don't have to be contracts at all (the actual types can be specified in generic IMsg directly), but if one ID type is wildly different in nature than the other, an interface such as this might make sense.

public interface IMsgId
{
 // ?
}

public interface INewMsgId : IMsgId
{
}

public interface ILegacyMsgId : IMsgId
{
}

public interface IMsg<out TId>
   where TId : IMsgId
{
   TId MessageId { get; }

   byte[] MsgBytes { get; }
}

// if it is sensible, you can use the following interfaces to create definitive new and legacy message contracts

public interface INewMsg : IMsg<INewMsgId>
{
}

public interface ILegacyMsg : IMsg<ILegacyMsgId>
{
}

这是一个实现示例:

public class LegacyMsgId : ILegacyMsgId
{
    public LegacyMsgId(int id)
    {
      Id = id;
    }

    public int Id { get; private set; }


    public override string ToString()
    {
        return "Legacy Message #" + Id;
    }
}

public class NewMsgId : INewMsgId
{
    public NewMsgId(int id)
    {
        Id = id;
    }

    public int Id { get; private set; }

    public override string ToString()
    {
        return "New Message #" + Id;
    }
}

public class NewMsg : INewMsg
{
    public NewMsg(int id)
    {
        MessageId = new NewMsgId(id);
    }

    public NewMsgId MessageId { get; private set; }

    INewMsgId IMsg<INewMsgId>.MessageId { get { return MessageId; } }

    public byte[] MsgBytes { get; private set; }
}

public class LegacyMsg : ILegacyMsg
{
    public LegacyMsg(int id)
    {
        MessageId = new LegacyMsgId(id);
    }

    public LegacyMsgId MessageId { get; private set; }

    ILegacyMsgId IMsg<ILegacyMsgId>.MessageId { get { return MessageId; } }

    public byte[] MsgBytes { get; private set; }
}

和用法:

var messages = new List<IMsg<IMsgId>>();
messages.Add(new NewMsg(20));
messages.Add(new LegacyMsg(11));

foreach(var message in messages)
{
    Console.WriteLine(message.MessageId);
}
于 2012-06-13T14:48:17.407 回答
1

但是我的问题是,为 New_Msgs 提供一个新接口是否更有意义,它继承了 Msg 并覆盖了 MessageId

您不能有与overrides 的接口,但是您可以使用new,但这意味着两者具有相同的签名,这里不是这种情况。

如果您要定义新功能,它与以前的接口不向后兼容,那么我会建议类似interface Msg2which 不相关(即不继承)到interface Msg. 由于一个类可以实现多个接口,那么您的实际实现可以处理两个接口实现,同时保持定义分开,从而允许任何未来的代码选择是否处理遗留实现。

于 2012-06-13T14:50:20.907 回答
0

您可以通过多种方式处理此问题:

  1. 您可以重构代码以用子类替换类型代码。枚举基本上是具有一点类型安全性的普通常量,不适合 OOP 和版本控制。在 C# 中,它们不能扩展:

    public interface IMsg
    {
        // let `MessageType` be a class
        MessageType Type { get; }
        byte[] Data { get; }
    }
    
  2. 或者,您可以使用普通的 int ID,并将特定 MessageID 背后的实际含义与包含数据的简单对象分开。

    // let Msg be a dumb data object
    public interface IMsg
    {
        int Id { get; }
        byte[] Data { get; }
    }
    
    // and then keep their types weakly-typed
    private readonly Dictionary<int, String> MessageNames;
    
    // and you can also provide various type-based functionality
    // during runtime
    private readonly Dictionary<int, IParser> Parsers;
    

I附带说明一下,在所有接口名称前加上大写字母是 .NET 命名约定。

于 2012-06-13T15:07:28.210 回答