Принудительно заставить экземпляр класса использовать интерфейс

#c# #oop

#c# #ООП

Вопрос:

Как заставить WebSocketClient экземпляр класса использовать IWebSocketClient интерфейс в его создании?

Например У меня нет ConnectAsync метода, указанного в интерфейсе, и я ожидаю, что код не позволит мне его вызвать.

 IWebSocketClient webSocketClient = new WebSocketClient(uri); await webSocketClient  .ConnectAsync(CancellationToken.None) // ConnectAsync is missing which is expected behavior  .ConfigureAwait(false);  
 var webSocketClient = new WebSocketClient(uri); await webSocketClient  .ConnectAsync(CancellationToken.None) // it allows me to call it, which is not expected behavior  .ConfigureAwait(false);  

Отрывок

 public interface IWebSocketClient : IDisposable {  WebSocketState State { get; } }  public class WebSocketClient : IWebSocketClient {  public WebSocketClient(Uri uri)  {  }   /// lt;inheritdoc /gt;  public WebSocketState State =gt; _webSocket.State;   public async Task ConnectAsync(CancellationToken cancellationToken)  {  ...  } }  

Комментарии:

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

2. @AnthonyPegram, хорошая идея. Я также помню , что я мог бы сделать явную реализацию интерфейса async Task IWebSocketClient.ConnectAsync(CancellationToken cancellationToken) , которая побуждает людей использовать интерфейс.

3. Да, явная реализация работает для этого метода, если он объявлен интерфейсом, но вы, по-видимому, намеренно исключили его из определения интерфейса. Но если вы хотите, чтобы этот метод на самом деле был виден только через интерфейс, то лучше всего использовать явный способ.

4. @AnthonyPegram, мне тоже нравится фабричный метод. Вы предлагаете public static IWebSocketClient Create(Uri uri) =gt; new WebSocketClient(uri); и сами сделать конструктор internal ?

5. Если конструктор является внутренним, то любой класс в сборке может вызывать его, поэтому, если вы собираетесь использовать этот класс в той же сборке (и не хотите прямого построения), он должен быть более ограниченным. Начните с private (это означает, что класс предоставляет свой собственный фабричный метод) и работайте дальше.

Ответ №1:

Создайте базовый абстрактный класс, а затем реализуйте интерфейс в виде абстрактных методов. Это заставит все подклассы реализовать эти методы.

Правка: Перечитывая ваш вопрос, я задаюсь вопросом, не неправильно ли я понял вашу проблему. Если вы хотите, чтобы у IWebSocketClient всегда был метод ConnectAsync, вы просто добавляете этот метод в интерфейс. Прямо сейчас интерфейс имеет только состояние, а не метод ConnectAsync.

Если в качестве альтернативы вы не хотите, чтобы какой-либо другой код мог вызывать ConnectAync, вам нужно сделать его закрытым.