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

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

しかし、私が疑問に思っているのは、Msg を継承して MessageId をオーバーライドする New_Msgs 用の新しいインターフェイスを用意する方が理にかなっているということです。

overridesとのインターフェースを持つことはできませんが、使用することはできますnewが、これは両方が同じ署名を持っていることを意味しますが、ここではそうではありません。

新しい機能を定義している場合、それは以前のインターフェースとの下位互換性がinterface Msg2ないため、関連していない (つまり、継承していない) ようなものをお勧めしinterface Msgます。クラスは複数のインターフェイスを実装できるため、実際の実装では定義を分離したまま両方のインターフェイス実装を処理できるため、今後のコードで従来の実装を処理するかどうかを選択できるようになります。

于 2012-06-13T14:50:20.907 に答える
1

他の誰かがこのインターフェイスを使用している場合 (どちらのソリューションでも問題ないと思います)、「Obsolete」タグを使用して、他の開発者に更新について警告することをお勧めします。

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 に答える
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 に答える