定义这个通用接口以便编译的最简洁方法是什么?

时间:2010-03-02 02:19:13

标签: c# .net generics c#-4.0

因为,两个具有相同参数但返回值不同的方法将无法编译。在不失去清晰度的情况下定义此界面的最佳方法是什么?

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 个答案:

答案 0 :(得分:5)

主要问题是您正在尝试同时从两端查看双工通道。数据在双工通道上双向传播,但仍有明确的终点。你在一端发送的是你收到的另一端。

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>

答案 1 :(得分:4)

重命名这两种方法。它们仅因返回类型而不同。

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

注意,我没有测试过这个。试试这个。

R Receive<R>(int timeout = -1);

答案 2 :(得分:3)

问题确实存在两种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); 
} 

正如Josh所说,我也会摆脱ReceiveSend方法。为什么?因为它使界面的实现变得简单,您可以使用ReceiveSend作为扩展方法轻松提供TryReceiveTrySend的实现。所以,你最终得到了一个界面:

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