c# - 等效的隐式运算符 : why are they legal?

标签 c# .net implicit ambiguity implicit-conversion

更新!

请参阅下面我对 C# 规范的一部分的剖析;我想我一定遗漏了什么,因为对来说,我在这个问题中描述的行为实际上违反了规范。

更新2!

好的,经过进一步思考,并根据一些评论,我想我现在明白发生了什么事了。规范中的“源类型”一词指的是从 转换的类型——即我下面示例中的Type2——这仅仅意味着编译器能够将候选者缩小到定义的两个运算符(因为 Type2 是两者的源类型)。但是,它不能进一步缩小选择范围。所以规范中的关键词(因为它适用于这个问题)是“源类型”,我之前将其误解(我认为)为“声明类型”。


原始问题

假设我定义了这些类型:

class Type0
{
    public string Value { get; private set; }

    public Type0(string value)
    {
        Value = value;
    }
}

class Type1 : Type0
{
    public Type1(string value) : base(value) { }

    public static implicit operator Type1(Type2 other)
    {
        return new Type1("Converted using Type1's operator.");
    }
}

class Type2 : Type0
{
    public Type2(string value) : base(value) { }

    public static implicit operator Type1(Type2 other)
    {
        return new Type1("Converted using Type2's operator.");
    }
}

然后说我这样做:

Type2 t2 = new Type2("B");
Type1 t1 = t2;

显然这是不明确的,因为不清楚应该使用哪个 implicit 运算符。我的问题是——因为我看不到解决这种歧义的任何方法(这不像我可以执行一些显式转换来澄清我想要的版本),但上面的类定义确实可以编译-- 为什么编译器会完全允许那些匹配的隐式运算符?


剖析

好吧,我将逐步浏览 Hans Passant 引用的 C# 规范的摘录,以试图理解这一点。

Find the set of types, D, from which user-defined conversion operators will be considered. This set consists of S (if S is a class or struct), the base classes of S (if S is a class), and T (if T is a class or struct).

我们正在将 Type2 (S) 转换为 Type1 ( T)。所以这里的 D 似乎包括示例中的所有三种类型:Type0(因为它是 S 的基类),Type1 (T) 和Type2 (S)。

Find the set of applicable user-defined conversion operators, U. This set consists of the user-defined implicit conversion operators declared by the classes or structs in D that convert from a type encompassing S to a type encompassed by T. If U is empty, the conversion is undefined and a compile-time error occurs.

好的,我们有两个运算符满足这些条件。 Type1中声明的版本符合要求,因为Type1D中,它是从Type2(显然包含S) 到 Type1(显然包含在 T 中)。 Type2 中的版本 出于完全相同的原因满足要求。所以 U 包括这两个运算符。

最后,关于在 U 中找到运算符的最具体的“源类型”SX:

If any of the operators in U convert from S, then SX is S.

现在,U 中的两个 运算符都从 S 转换而来——所以这告诉我 SX 是 < strong>S.

这是否意味着应该使用 Type2 版本?

但是等等!我很困惑!

我不能定义运算符的Type1版本吗,在这种情况下,唯一剩下的候选者将是Type1的版本,但根据规范 SX 将是 Type2?这似乎是一种可能的情况,其中规范强制执行不可能的事情(即,在 Type2 中声明的转换实际上不存在时应该使用)。

最佳答案

归根结底,不能完全成功地禁止。你和我可以发布两个程序集。他们我们可以开始使用彼此的程序集,同时更新我们自己的程序集。然后我们每个人都可以在每个程序集中定义的类型之间提供隐式转换。只有当我们发布下一个版本时,才能捕获到它,而不是在编译时。

不试图禁止不能禁止的事情是有好处的,因为它有利于清晰和一致(这对立法者来说是一个教训)。

关于c# - 等效的隐式运算符 : why are they legal?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3561619/

相关文章:

C# SQL 输出代码问题

c# - 如何让 BackgroundWorker ProgressChanged 事件按顺序执行?

c# - FIPS 验证加密算法的问题

scala - Scala 中的惰性 val 和隐式参数

Scala 集合总和可与重载加法一起使用

scala - 找不到懒惰的隐式 val

c# - 单一职责原则用法如何正确调用子方法?

c# - 电子商务网站的不同搜索结果

c# - 如何从音频文件中获取 musicbrainz 轨道信息

c# - Entity Framework - 子模型的 "cannot insert duplicate object"