Какой самый чистый способ определить этот универсальный интерфейс, чтобы он компилировался? - PullRequest
2 голосов
/ 02 марта 2010

Поскольку два метода с одинаковыми параметрами, но с разными возвращаемыми значениями, компилироваться не будут. Каков наилучший способ определить этот интерфейс без потери ясности?

public interface IDuplexChannel<T, U>
{
    void Send(T value, int timeout = -1);
    void Send(U value, int timeout = -1);
    bool TrySend(T value, int timeout = -1);
    bool TrySend(U value, int timeout = -1);
    T Receive(int timeout = -1);
    U Receive(int timeout = -1);
    bool TryReceive(out T value, int timeout = -1);
    bool TryReceive(out U value, int timeout = -1);
}

Я подумал об использовании params, но это сделало бы его немного неловким в использовании.

public interface IDuplexChannel<T, U>
{
    void Send(T value, int timeout = -1);
    void Send(U value, int timeout = -1);
    bool TrySend(T value, int timeout = -1);
    bool TrySend(U value, int timeout = -1);
    void Receive(out T value, int timeout = -1);
    void Receive(out U value, int timeout = -1);
    bool TryReceive(out T value, int timeout = -1);
    bool TryReceive(out U value, int timeout = -1);
}

Универсальная версия, немного громоздкая, но работает.

public interface IDuplexChannel<T, U>
{
    void Send(T value, int timeout = -1);
    void Send(U value, int timeout = -1);
    bool TrySend(T value, int timeout = -1);
    bool TrySend(U value, int timeout = -1);
    V Receive<V>(int timeout = -1) where V : T, U;
    bool TryReceive(out T value, int timeout = -1);
    bool TryReceive(out U value, int timeout = -1);
}

Ответы [ 3 ]

5 голосов
/ 02 марта 2010

Основная проблема заключается в том, что вы пытаетесь одновременно просматривать дуплексный канал с обоих концов. Данные передаются в двух направлениях по дуплексному каналу, но все еще существуют определенные конечные точки. То, что вы отправляете на одном конце, - это то, что вы получаете на другом.

public interface IDuplexChannel<TSend, TReceive>
{
    void Send(TSend data);
    TReceive Receive();
}

Тем не менее, вы все равно должны использовать WCF, особенно , поскольку вы используете .NET 4.0.

Редактировать: Картинки

        "PERSON" A                                     "PERSON" B
            O            int ----------------->            O
           -|-           <-------------- string           -|-
           / \                                            / \
IDuplexChannel<int, string>                     IDuplexChannel<string, int>
4 голосов
/ 02 марта 2010

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

T Receive(int timeout = -1);
U Receive(int timeout = -1);

Обратите внимание, я не проверял это. Попробуйте это.

R Receive<R>(int timeout = -1);
3 голосов
/ 02 марта 2010

Проблема действительно в том, что есть два Receive метода, которые отличаются только типом возвращаемого значения. Поскольку ваш тип представляет дуплексный канал, вам пришлось дублировать все в интерфейсе - я полагаю, что более простой подход - определить тип, который позволяет вам представлять "либо T, либо U" . Это очень похоже на Tuple<T, U>, который сейчас находится в .NET, что позволяет вам представлять "и T, и U" . Сигнатура типа может выглядеть так:

// Represents either a value of type T or a value of type U
class Either<T, U> { 
  public bool TryGetFirst(out T val);
  public bool TryGetSecond(out U val);
}

// For constructing values of type Either<T, U>
static class Either {
  public static Either<T, U> First<T, U>(T val);
  public static Either<T, U> Second<T, U>(U val);
}

Пример использования этого класса может выглядеть следующим образом:

var val = Either.First<int, string>(42);

int num;
string str;
if (val.TryGetFirst(out num)) 
  Console.WriteLine("Got number: {0}", num);
else if (val.TryGetSecond(out str)) 
  Console.WriteLine("Got string: {0}", str);

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

public interface IDuplexChannel<T, U> { 
    void Send(Either<T, U> value, int timeout = -1); 
    bool TrySend(Either<T, U> value, int timeout = -1); 
    Either<T, U> Receive(int timeout = -1); 
    bool TryReceive(out Either<T, U> value, int timeout = -1); 
} 

Как предполагает Джош, я бы также избавился от методов Receive и Send. Зачем? Потому что это делает реализацию интерфейса простой, и вы можете легко обеспечить реализацию Receive и Send в терминах TryReceive и TrySend в качестве метода расширения. Итак, вы получите интерфейс:

public interface IDuplexChannel<T, U> { 
    bool TrySend(Either<T, U> value, int timeout = -1); 
    bool TryReceive(out Either<T, U> value, int timeout = -1); 
} 

И методы расширения будут выглядеть примерно так:

public static Either<T, U> Receive
    (this IDuplexChannel<T, U> ch, int timeout = -1) {
  Either<T, U> v;
  if (!ch.TryReceive(out v, timeout)) throw new Exception(...);
  return v;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...