2012-06-13 4 views
1

У меня есть пара базовых сообщений Перечисления, которые я вставляю в интерфейс для их управления. Однако, как я это делаю, мне нужно поддерживать сообщения Legacy, добавляя новые. Каков наилучший способ сделать это?Интерфейс с несколькими определениями C#

Это общая идея интерфейса 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.
Я понимаю, что оба решения могут работать, но мне интересно, как еще один разработчик смотрит на такое решение, что имеет больше смысла?

ответ

2

Интерфейсы не могут переопределяться, но вы можете добавлять новые элементы в контракт через интерфейс.

Если поведение будет изменяться между реализациями таким образом, чтобы они не были обратно совместимы, тогда вы должны создать совершенно новый интерфейс/реализацию без отношения к старому, поскольку кто-то может создать экземпляр нового, и передать его потребителю, ожидающему старую.

Одна реализация может реализовать оба интерфейса для обеспечения максимально возможной совместимости. Если интерфейсы имеют перекрытие элементов, то вы можете использовать явную реализацию интерфейса для поддержки обоих интерфейсов.

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); 
} 
1

Однако то, что я спрашиваю это он делает больше смысла иметь новый интерфейс для New_Msgs , который наследует Msg и переопределяет MessageId

У вас не может быть интерфейса с override, но вы можете использовать new, но это означает, что обе имеют одну и ту же подпись, которая здесь не имеет места.

Если вы определяете новые функции, которые не совместимы с предыдущим интерфейсом, я бы предложил что-то вроде interface Msg2, которое не связано (то есть не наследует) до interface Msg. Поскольку класс может реализовывать несколько интерфейсов, тогда ваша фактическая реализация может обрабатывать обе реализации интерфейса, сохраняя отдельные определения и тем самым позволяя любому будущему коду выбирать, следует ли обрабатывать устаревшую реализацию.

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 
{ 
{ 
+0

Другие будут использовать его, однако, к сожалению, Legacy не устарело, они хотят его перетащить и полностью поддерживать, пока не последует уведомление ... :-( – Prediluted

0

Вы можете иметь дело с несколькими способами:

  1. Вы можете реорганизовать свой код replace type code with subclasses. Перечисления представляют собой в основном простые константы с минимальной безопасностью типа и не подходят для ООП и управления версиями. В C#, они не могут быть расширен:

    public interface IMsg 
    { 
        // let `MessageType` be a class 
        MessageType Type { get; } 
        byte[] Data { get; } 
    } 
    
  2. Или, вы можете использовать простые ИНТЫ идентификаторов, и отделить реальное значение за конкретное MessageIDs от простого объекта, который содержит данные.

    // 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; 
    

Как примечание стороны, это .NET именование конвенции предварять капитал I для всех имен интерфейсов.

Смежные вопросы