特定
class Either<A, B> {
public Either(A x) {}
public Either(B x) {}
}
Run Code Online (Sandbox Code Playgroud)
当两个类型参数相同时,如何消除两个构造函数之间的歧义?
例如,这一行:
var e = new Either<string, string>("");
Run Code Online (Sandbox Code Playgroud)
失败:
以下方法或属性之间的调用不明确:'Program.Either.Either(A)'和'Program.Either.Either(B)'
我知道,如果我给出的参数不同的名称(例如,A a和B b,而不是仅仅x),我可以使用命名参数来消除歧义(例如new Either<string, string>(a: "")).但我很想知道如何在不改变定义的情况下解决这个问题Either.
编辑:
你可以编写几个智能构造函数,但我很想知道是否Either可以直接调用构造函数而不会产生歧义.(或者除了这个之外还有其他"技巧").
static Either<A, B> Left<A, B>(A x) {
return new Either<A, B>(x);
}
static Either<A, B> Right<A, B>(B x) {
return new Either<A, B>(x);
}
var e1 = Left<string, string>("");
var e2 = Right<string, string>("");
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 49
当两个类型参数相同时,如何消除两个构造函数之间的歧义?
我首先回答你的问题,然后用一个实际的答案来完成,让你解决这个问题.
你不必这样做,因为你不应该首先让自己进入这个位置.创建泛型类型是一种设计错误,可以使成员签名以这种方式统一.永远不要写那样的课.
如果你回头看原来的C#2.0规范,你会发现原来的设计是有编译器检测的通用类型,它是在任何可能的方式为这种问题出现,并且使类声明非法.这使它成为已发布的规范,尽管这是一个错误; 设计团队意识到这条规则过于严格,因为以下情况:
class C<T>
{
public C(T t) { ... }
public C(Stream s) { ... deserialize from the stream ... }
}
Run Code Online (Sandbox Code Playgroud)
说这个类是非法的是很奇怪的,因为你可能会说C<Stream>,然后无法消除构造函数的歧义.相反,在重载决策中添加了一条规则,即如果之间有选择(Stream),(T where Stream is substituted for T)那么前者获胜.
因此,这种统一是非法的规则被废除,现在允许.然而,制作以这种方式统一的类型是一个非常非常糟糕的主意.在某些情况下,CLR处理得很差,而且编译器和开发人员都很困惑.例如,你是否想要猜测这个程序的输出?
using System;
public interface I1<U> {
void M(U i);
void M(int i);
}
public interface I2<U> {
void M(int i);
void M(U i);
}
public class C3: I1<int>, I2<int> {
void I1<int>.M(int i) {
Console.WriteLine("c3 explicit I1 " + i);
}
void I2<int>.M(int i) {
Console.WriteLine("c3 explicit I2 " + i);
}
public void M(int i) {
Console.WriteLine("c3 class " + i);
}
}
public class Test {
public static void Main() {
C3 c3 = new C3();
I1<int> i1_c3 = c3;
I2<int> i2_c3 = c3;
i1_c3.M(101);
i2_c3.M(102);
}
}
Run Code Online (Sandbox Code Playgroud)
如果你在打开警告的情况下编译它,你会看到我添加的警告,解释为什么这是一个非常非常糟糕的主意.
不,真的:当两个类型参数相同时,如何消除两个构造函数之间的歧义?
像这样:
static Either<A, B> First<A, B>(A a) => new Either<A, B>(a);
static Either<A, B> Second<A, B>(B b) => new Either<A, B>(b);
...
var ess1 = First<string, string>("hello");
var ess2 = Second<string, string>("goodbye");
Run Code Online (Sandbox Code Playgroud)
这就是本课程应该首先设计的方式.该Either课程的作者应该写
class Either<A, B>
{
private Either(A a) { ... }
private Either(B b) { ... }
public static Either<A, B> First(A a) => new Either<A, B>(a);
public static Either<A, B> Second(B b) => new Either<A, B>(b);
...
}
...
var ess = Either<string, string>.First("hello");
Run Code Online (Sandbox Code Playgroud)