相当于隐含运营商:他们为什么合法的吗? [英] Equivalent implicit operators: why are they legal?

查看:146
本文介绍了相当于隐含运营商:他们为什么合法的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看我下面的C#规范的一部分的夹层;我想我一定是失去了一些东西,因为为它看起来像的行为,我描述了这个问题实际上违反了规范。

See my dissection of a portion of the C# spec below; I think I must be missing something, because to me it looks like the behavior I'm describing in this question actually violates the spec.

确定,在进一步反思,并根据一些意见,我想我现在明白发生了什么事情。在规范的话源类型指的类型被转换 - 即 2型在我下面的例子 - 它只是手段编译器能够缩小候选人下降到两家运营商定义的(因为 2型是为源型)。然而,它不能再缩小选择。所以关键词语的规范(因为它适用于这个问题)的源类型,这是我previously misinter preTED(我认为)的意思是声明类型。

OK, upon further reflection, and based on some comments, I think I now understand what's going on. The words "source type" in the spec refer to the type being converted from -- i.e., Type2 in my example below -- which simply means that the compiler is able to narrow the candidates down to the two operators defined (since Type2 is the source type for both). However, it cannot narrow the choices any further. So the key words in the spec (as it applies to this question) are "source type", which I previously misinterpreted (I think) to mean "declaring type."

假设我已经定义了这些类型:

Say I have these types defined:

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.");
    }
}

然后说我这样做:

Then say I do this:

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

显然,这是不明确的,因为它不清楚哪个经营者应使用。我的问题是 - 因为我看不到的任何的方式来解决这种不确定性(这是不喜欢我可以执行一些明确的投澄清我想要的版本),但类定义上面做编译 - 为什么编译器还允许那些在所有符合条件的运营商

Obviously this is ambiguous, as it is not clear which implicit operator should be used. My question is -- since I cannot see any way to resolve this ambiguity (it isn't like I can perform some explicit cast to clarify which version I want), and yet the class definitions above do compile -- why would the compiler allow those matching implicit operators at all?

OK,我要一步通过C#规范由Hans帕桑特引述的摘录,试图理解这一点。

OK, I'm going to step through the excerpt of the C# spec quoted by Hans Passant in an attempt to make sense of this.

找到所述一组类型,D,从该   用户自定义转换操作   加以考虑。此集合包括S   (如果S是类或结构),基   类S(如果S是一个类),及T的   (如果T为类或结构)。

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).

我们正在转换的 2型取值)的类型1 T )。如此看来,这里的ð将包括三种类型的例子:键入0 (因为它是取值),类型1 T )和 2型取值)。

We're converting from Type2 (S) to Type1 (T). So it seems that here D would include all three types in the example: Type0 (because it is a base class of S), Type1 (T) and Type2 (S).

查找该组适用   用户自定义转换操作,U.   这个集包括用户定义的   隐式转换操作符声明   通过在D类或结构的   从类型包含S键转换   被T型包围如果U是   空,转换是未定义的   一个发生编译时错误。

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.

好了,我们已经得到了两家运营商满足这些条件。 在类型1声明的版本是否符合要求,因为类型1 ð并从转换 2型(这显然包含的取值),以类型1 (这显然是由<强包围> T )。该版本 2型的满足完全相同的原因的要求。因此, U 包括这两个运营商的。

All right, we've got two operators satisfying these conditions. The version declared in Type1 meets the requirements because Type1 is in D and it converts from Type2 (which obviously encompasses S) to Type1 (which is obviously encompassed by T). The version in Type2 also meets the requirements for exactly the same reasons. So U includes both of these operators.

最后,相对于寻找最具体的源类型 SX 的运营商在 U

Lastly, with respect to finding the most specific "source type" SX of the operators in U:

如果有任何的U中操作符从S转换,则SX为S

现在,的两个的运营商 U 从转换的取值 - 所以这告诉我, SX 是<强>取值

Now, both operators in U convert from S -- so this tells me that SX is S.

这是否意味着 2型版本应该被使用?

Doesn't this mean that the Type2 version should be used?

别急!我很困惑!

我不能有确定类型1 的版本,运营商,在这种情况下,唯一剩下的候选人将类型1 的版本,但根据该规范的 SX 2型?这似乎是在规范强制要求的东西是不可能的一个可能的方案(即在转换中 2型时,应当使用实际上不存在的声明)。

Couldn't I have only defined Type1's version of the operator, in which case, the only remaining candidate would be Type1's version, and yet according to the spec SX would be Type2? This seems like a possible scenario in which the spec mandates something impossible (namely, that the conversion declared in Type2 should be used when in fact it does not exist).

推荐答案

我们真的不希望它是一个编译时错误只是定义其转换的可能的引起歧义。假设我们改变键入0存储双,出于某种原因,我们希望提供单独的转换为符号整数和无符号整数。

We don't really want it to be a compile-time error just to define conversions which might cause ambiguity. Suppose that we alter Type0 to store a double, and for some reason we want to provide separate conversions to signed integer and unsigned integer.

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

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

    public static implicit operator Int32(Type0 other)
    {
        return (Int32)other.Value;
    }

    public static implicit operator UInt32(Type0 other)
    {
        return (UInt32)Math.Abs(other.Value);
    }

}

这编译好了,我可以使用同时使用的转换与

This compiles fine, and I can use use both conversions with

Type0 t = new Type0(0.9);
int i = t;
UInt32 u = t;

不过,这是一个编译错误尝试浮动F =牛逼,因为无论的隐式转换可以用来去,然后可以转换为float整数类型

However, it's a compile error to try float f = t because either of the implicit conversions could be used to get to an integer type which can then be converted to float.

我们只希望编译器抱怨这些更复杂的模糊性实际上是在使用它们时,因为我们希望上面的类型0编译。为了保持一致性,简单的模糊性也应引起你使用它的点错误,而不是当你定义它。

We only want the compiler to complain about these more complex ambiguities when they're actually used, since we'd like the Type0 above to compile. For consistency, the simpler ambiguity should also cause an error at the point you use it rather than when you define it.

修改

由于汉斯带走了他的答案,所引用的规范,这里的通过C#规范,确定转换是否有歧义的部分快速运行,具有确定的U给是集合所有这有可能做的工作的转换:

Since Hans removed his answer which quoted the spec, here's a quick run through the part of the C# spec that determines whether a conversion is ambiguous, having defined U to be the set of all the conversions which could possibly do the job:

      
  • 找到最精确的源类型,SX,在U中操作符:   
        
    • 如果任何运营商U中从S转换,则SX为s。
    •   
    • 否则,SX是最被包含类型的运营商在美国的目标类型的组合。如果不存在包含程度最大的类型可以发现,则转换是不明确的,并且发生编译时错误。
    •   
    • Find the most specific source type, SX, of the operators in U:
      • If any of the operators in U convert from S, then SX is S.
      • Otherwise, SX is the most encompassed type in the combined set of target types of the operators in U. If no most encompassed type can be found, then the conversion is ambiguous and a compile-time error occurs.

    达旨,我们preFER的转换而转换直接从S,否则我们preFER这是类型为最简单的转换S键。在这两个例子中,我们从两大转换可用。如果没有从 2型的转换,我们会preFER一个转换,从键入0 过一个来自对象。如果没有一种类型显然是更好的选择要转换,我们在这里失败。

    Paraphrased, we prefer a conversion which converts directly from S, otherwise we prefer the type which is "easiest" to convert S to. In both examples, we have two conversions from S available. If there were no conversions from Type2, we'd prefer a conversion from Type0 over one from object. If no one type is obviously the better choice to convert from, we fail here.

        
    • 找到最具体的目标类型,德克萨斯州,该U中操作符:   
          
      • 如果任何一个运营商在ü转换为T,则TX为T。
      •   
      • 否则,德克萨斯州是最大包含类型的运营商在美国的目标类型的组合。如果不存在最大包含类型可以发现,则转换是不明确的,并且发生编译时错误。
      •   
      • Find the most specific target type, TX, of the operators in U:
        • If any of the operators in U convert to T, then TX is T.
        • Otherwise, TX is the most encompassing type in the combined set of target types of the operators in U. If no most encompassing type can be found, then the conversion is ambiguous and a compile-time error occurs.

      此外,我们会preFER直接转换为T,但我们会解决这是最简单的转换到T.在丹的例子类型,我们有两个转换到T可用。在我的例子中,可能的目标是的Int32 UInt32的,也不是一个比其他更好的匹配,所以这就是转换失败。编译器没有办法知道是否浮动F =牛逼办法浮动F =(浮点)(的Int32)T 浮动F =(浮点)(UInt32的)T

      Again, we'd prefer to convert directly to T, but we'll settle for the type that's "easiest" to convert to T. In Dan's example, we have two conversions to T available. In my example, the possible targets are Int32 and UInt32, and neither is a better match than the other, so this is where the conversion fails. The compiler has no way to know whether float f = t means float f = (float)(Int32)t or float f = (float)(UInt32)t.

          
      • 如果U中一个用户定义的转换操作符从SX到TX,那么这就是最具体的转换运算符。如果没有这样的运营商存在,或者,如果不止一个这样的操作符存在,则转换是不明确的,并且发生编译时错误。
      •   

      在丹的例子,我们在这里失败,因为我们有两个转换,从左边到SX TX。我们可能没有从SX转换到TX的,如果我们决定SX和TX时选择了不同的转换。例如,如果我们有一个 Type1a 类型1 导出,那么我们会从转换类型2 Type1a 键入0 类型1 这仍然给我们SX = 2型和TX =类型1,但我们实际上并没有从类型2到类型1任何转换。这是正常的,因为这真的是不明确的。编译器不知道是否2型转换为Type1a,然后转换为类型1,或转换为键入0第一,以便它可以使用该转换类型1。

      In Dan's example, we fail here because we have two conversions left from SX to TX. We could have no conversions from SX to TX if we chose different conversions when deciding SX and TX. For example, if we had a Type1a derived from Type1, then we might have conversions from Type2 to Type1a and from Type0 to Type1 These would still give us SX=Type2 and TX=Type1, but we don't actually have any conversion from Type2 to Type1. This is OK, because this really is ambiguous. The compiler doesn't know whether to convert Type2 to Type1a and then cast to Type1, or cast to Type0 first so that it can use that conversion to Type1.

      这篇关于相当于隐含运营商:他们为什么合法的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆