在==操作符重载解析与变异泛型委托类型 [英] Overload resolution on operator == with variant generic delegate types

查看:265
本文介绍了在==操作符重载解析与变异泛型委托类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是重载的精确的规则与 == 委托类型的两个表达式?



考虑下面的代码(其中使用系统; 需要):

 静类ProgramA 
{
静态无效TargetMethod(obj对象)
{
}

静态无效的主要()
{
动作<对象>实例1 = TargetMethod;
动作<对象> INSTANCE2 = TargetMethod;

动作<串GT; A1 = INSTANCE1;
动作<&乌里GT; A2 = INSTANCE2;

Console.WriteLine((对象)A1 ==(对象)A2);
Console.WriteLine((代表)A1 ==(代表)A2);
Console.WriteLine((动作<对象>)A1 ==(动作<对象>)A2);

Console.WriteLine(A1 == A2); //警告CS0253:可能无意引用比较;得到一个值比较,铸就右侧键入'System.Action<串>'
}
}

说明:



实例1 INSTANCE2 是相同的运行时类型的两个独立的情况下,一般动作<在T> 这就是逆变 T 。这些情况是不同的,但等于,因为它们的拥有相同的目标。



A1 A2 相同实例1 INSTANCE2 ,但因为动作<的逆变;而在T> 存在的的从动作<对象> ; 到每个动作<串> 动作<的System.Uri方式>



现在,在C#语言规范有(除其他重载)这些运算符==

 布尔运算符==(对象x,对象Y); //§7.10.6
布尔运算符==(System.Delegate x,System.Delegate y)的; //§7.10.8



目前的Visual C#编译器来实现,如果所引用检查只是第一个是相同的(白细胞介素实际上不叫喜欢 object.ReferenceEquals A mscorlib程序方法,但这样会产生相同的结果),同时通过调用<一个实现第二个HREF =http://msdn.microsoft.com/en-us/library/system.delegate.op_equality.aspx> Delegate.op_Equality 方法其中看起来,即使它是由C#语言规范中定义的组件内用户自定义操作符,所以也许不是用户自定义中的规范(?)的感觉。



注意§7.10.8是有点混乱,因为它说的每个委托类型都隐式提供下列预定义的比较运算符[S]的,然后给出了与运营商的(System.Delegate,System.Delegate)签名。这只是的有一个的运营商,而不是一个每委托类型?这似乎是我的问题很重要。



这是不奇怪的三首的WriteLine ,分别给予了我上面说的。



问:但是为什么第四的WriteLine 导致所使用的(对象,对象)超载?



有确实存在的隐式引用转换动作<> (或任何其他委托类型)为 System.Delegate ,那么为什么不能在这里使用?重载决策应该更喜欢在(对象,对象)选项。



当然,没有任何的 的转换>动作<串> 和动作<乌里> ,但为什么是相关的?如果我创造我自己的类 MyBaseClass 包含一个用户定义的 ==操作符(MyBaseClass X,MyBaseClass Y)和我创建两个不相关的派生类,那么我的 == 运营商仍然会使用(左,右操作数无法转换为对方,但都转换为 MyBaseClass )。






只是为了完整性,这里是协方差类似的例子 Func键<出TResult> ),而不是逆变:

 静态类Programf到
{
静态字符串TargetMethod()
{
返回假的;
}

静态无效的主要()
{
Func键<串GT;实例1 = TargetMethod;
Func键<串GT; INSTANCE2 = TargetMethod;

Func键< ICloneable> F1 = INSTANCE1;
Func键< IConvertible> F2 = INSTANCE2;

Console.WriteLine((对象)F1 ==(对象)F2);
Console.WriteLine((代表)F1 ==(代表)F2);
Console.WriteLine((Func键<串GT;)F1 ==(Func键<串GT;)F2);

Console.WriteLine(F1 F2 ==); //警告CS0253:可能无意引用比较;得到一个值比较,铸就右侧键入'System.Func< System.ICloneable>'
}
}

有关我的问题上面,的其中的在C#语言规范它说,这应是非法的一个问题:

  Func键<串GT; G1 = ...; 
Func键<&乌里GT; G2 = ...;
Console.WriteLine(G1 == G2); //错误CS0019:运算符'=='不能应用于类型的操作数'System.Func<串>'和'System.Func<的System.Uri>'

我可以看到,编译器想通了,没有类型都不能来自字符串继承乌里(不像对 ICloneable IConvertible ),所以这(如果它是合法的),只能成为真正如果两个变量是,但如果它说,我不允许去做这个?在这种情况下,如果编译器选择了它不会有问题 ==操作符(对象,对象) ==操作符(委托代表),因为,正如我所说,它归结为检查,如果都为null引用,这两个重载做同样的方式。


解决方案

问:但是为什么第四的WriteLine导致的(对象,对象)重载使用




由于它的编译器的唯一选择: - )

 不能申请运营商'=='来操作数类型'System.Func< System.ICloneable>'和'System.Func< System.IConvertable>'

候选人是:

 布尔==(System.Delegate,System.Delegate)
布尔==(系统.FUNC< System.ICloneable>中System.Func< System.ICloneable>)
布尔==(System.Func< System.IConvertable>中System.Func< System.IConvertable>)

因此,使用你的(对象,对象),编译器发现一个不错的选择。



同为

 不能申请运营商操作==到类型的操作数'System.Action<串>'和System.Action<的System.Uri>'

候选人是:

 布尔==(System.Delegate,System.Delegate)
布尔==(System.Action<串>中System.Action<串GT; )
布尔==(System.Action<的System.Uri>中System.Action<&的System.Uri GT;)


What are the precise rules for overload resolution with == between two expressions of delegate type?

Consider the following code (where using System; is needed):

static class ProgramA
{
    static void TargetMethod(object obj)
    {
    }

    static void Main()
    {
        Action<object> instance1 = TargetMethod;
        Action<object> instance2 = TargetMethod;

        Action<string> a1 = instance1;
        Action<Uri> a2 = instance2;

        Console.WriteLine((object)a1 == (object)a2);
        Console.WriteLine((Delegate)a1 == (Delegate)a2);
        Console.WriteLine((Action<object>)a1 == (Action<object>)a2);

        Console.WriteLine(a1 == a2);  // warning CS0253: Possible unintended reference comparison; to get a value comparison, cast the right hand side to type 'System.Action<string>'
    }
}

Explanation:

instance1 and instance2 are two separate instances of the same run-time type, the generic Action<in T> which is contravariant in T. Those instances are distinct but Equals since they the have same targets.

a1 and a2 are the same as instance1 and instance2, but because of the contravariance of Action<in T> there exist implicit reference conversions from Action<object> to each of Action<string> and Action<System.Uri>.

Now, the C# Language Specification has (among other overloads) these operator ==:

bool operator ==(object x, object y);                   // §7.10.6
bool operator ==(System.Delegate x, System.Delegate y); // §7.10.8

The current Visual C# compiler realizes the first one by simply checking if the references are the same (the IL does not actually call a mscorlib method like object.ReferenceEquals, but that would give the same result), while it realizes the second one by calling Delegate.op_Equality method which looks like a "user-defined" operator inside that assembly even when it is defined by the C# Language Spec, so is maybe not "user-defined" in the sense of the spec(?).

Note that §7.10.8 is a little confusing because it says "Every delegate type implicitly provides the following predefined comparison operator[s]" and then gives the operator with the (System.Delegate, System.Delegate) signature. That is just one operator, not one for "every" delegate type? This seems important for my question.

It is not surprising that the three first WriteLine write False, True and True, respectively, given what I said above.

Question: But why does the fourth WriteLine lead to the (object, object) overload being used?

There does exist an implicit reference conversion from Action<> (or any other delegate type) to System.Delegate, so why can't that be used here? Overload resolution should prefer that over the (object, object) option.

Of course, there are no implicit conversions between Action<string> and Action<Uri>, but why is that relevant? If I create my own class MyBaseClass containing a user-defined operator ==(MyBaseClass x, MyBaseClass y) and I create two unrelated deriving classes, then my == operator will still be used (left and right operand not convertible to each other but both convertible to MyBaseClass).


Just for completeness, here is the analogous example with covariance (Func<out TResult>) instead of contravariance:

static class ProgramF
{
    static string TargetMethod()
    {
        return "dummy";
    }

    static void Main()
    {
        Func<string> instance1 = TargetMethod;
        Func<string> instance2 = TargetMethod;

        Func<ICloneable> f1 = instance1;
        Func<IConvertible> f2 = instance2;

        Console.WriteLine((object)f1 == (object)f2);
        Console.WriteLine((Delegate)f1 == (Delegate)f2);
        Console.WriteLine((Func<string>)f1 == (Func<string>)f2);

        Console.WriteLine(f1 == f2);  // warning CS0253: Possible unintended reference comparison; to get a value comparison, cast the right hand side to type 'System.Func<System.ICloneable>'
    }
}

A question related to my question above is, where in the C# Language Specification does it say that this shall be illegal:

Func<string> g1 = ...;
Func<Uri> g2 = ...;
Console.WriteLine(g1 == g2);  // error CS0019: Operator '==' cannot be applied to operands of type 'System.Func<string>' and 'System.Func<System.Uri>'

I can see that the compiler figured out that no type can ever inherit from both string and Uri (unlike the pair ICloneable and IConvertible), and so this (if it were legal) could only become true if both variables were null, but where does it say that I am not allowed to do this? In this case it would not matter if the compiler chose operator ==(object, object) or operator ==(Delegate, Delegate) since, as I said, it comes down to checking if both are null references, and both overloads do that in the same way.

解决方案

Question: But why does the fourth WriteLine lead to the (object, object) overload being used?

Because it's the only choice for the compiler :-)

Cannot apply operator '==' to operands of type 'System.Func<System.ICloneable>' and 'System.Func<System.IConvertable>'

candidates are:

bool==(System.Delegate, System.Delegate) 
bool==(System.Func<System.ICloneable>, System.Func<System.ICloneable>)
bool==(System.Func<System.IConvertable>, System.Func<System.IConvertable>)

so using your (object, object) is the best choice the compiler finds.

same for the Actions

Cannot apply operator '==' to operands of type 'System.Action<string>' and 'System.Action<System.Uri>'

candidates are:

bool==(System.Delegate, System.Delegate) 
bool==(System.Action<string>, System.Action<string>)
bool==(System.Action<System.Uri>, System.Action<System.Uri>)

这篇关于在==操作符重载解析与变异泛型委托类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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