C# 实现接口的类上的运算符重载

C# 实现接口的类上的运算符重载,c#,interface,operator-overloading,C#,Interface,Operator Overloading,假设我有一个接口IFoo和一个实现IFoo的类Foo。我想定义自己的逻辑,根据它们包含的数据确定两个Foo实例是否相等,并重载==&!=操作员在使用Foo时易于使用 如果我有两个Foo实例,都存储为Foo,那么这就可以了。然而,如果我有两个实例都存储为IFoo,那么我的重载操作符突然就不再被调用了。此外,由于我无法在IFoo接口上定义运算符,而且Foo运算符重载中至少有一个参数必须是Foo类型,因此我看不出有任何方法可以成功地在我的类型上重载运算符。这是正确的吗 还有,有人能澄清为什么会发生这种

假设我有一个接口IFoo和一个实现IFoo的类Foo。我想定义自己的逻辑,根据它们包含的数据确定两个Foo实例是否相等,并重载==&!=操作员在使用Foo时易于使用

如果我有两个Foo实例,都存储为Foo,那么这就可以了。然而,如果我有两个实例都存储为IFoo,那么我的重载操作符突然就不再被调用了。此外,由于我无法在IFoo接口上定义运算符,而且Foo运算符重载中至少有一个参数必须是Foo类型,因此我看不出有任何方法可以成功地在我的类型上重载运算符。这是正确的吗

还有,有人能澄清为什么会发生这种情况吗?通常,我希望我的Foos被存储为IFoos这一事实在确定调用哪个相等函数时应该无关紧要,因为从根本上说,它们仍然是Foos

非常感谢您的帮助

谢谢

编辑: 好的,因为我的意思似乎有点混乱,这里有一个例子,希望能澄清一点:

public interface IFoo
{
}

public class Foo : IFoo
{
    public static bool operator==(Foo left, Foo right)
    {
        ....
    }
}

Foo foo1 = new Foo();
Foo foo2 = new Foo();
bool comparison1 = foo1 == foo2    //This is successfully calling the overloaded operator

IFoo ifoo1 = foo1;
IFoo ifoo2 = foo2;
bool comparison2 = ifoo1 == ifoo2    //This isn't

运算符重载仅在编译时存在,编译后它只是对具有已知名称的特定静态方法的调用

C#编译器识别
Foo
的运算符重载,并将
a==b
替换为
Foo.op_等式(a,b)
。这意味着编译后的Foo类中存在非虚拟静态方法
op_Equality
。因此,不可能为接口重载运算符-接口不能有静态方法。此外,运算符方法是非虚拟的,这意味着实际方法是从变量类型而不是值类型解析的,因此编译器将根据
a
b
的变量类型(如果两者都是
IFoo
)查找可能的运算符重载,然后,它只能在
IFoo
类型中查找
op_Equality
,而该类型不能包含它


您只能为基于值类型解析的方法提供自定义逻辑,这些方法是虚拟方法,例如,您可以为Foo类型重写Equals方法,但它对
IFoo a==IFoo b
没有帮助,后者将解析为
对象。ReferenceEquals(a,b)

运算符重载仅在编译时存在,编译后它只是对具有已知名称的特定静态方法的调用

C#编译器识别
Foo
的运算符重载,并将
a==b
替换为
Foo.op_等式(a,b)
。这意味着编译后的Foo类中存在非虚拟静态方法
op_Equality
。因此,不可能为接口重载运算符-接口不能有静态方法。此外,运算符方法是非虚拟的,这意味着实际方法是从变量类型而不是值类型解析的,因此编译器将根据
a
b
的变量类型(如果两者都是
IFoo
)查找可能的运算符重载,然后,它只能在
IFoo
类型中查找
op_Equality
,而该类型不能包含它


您只能为基于值类型解析的方法提供自定义逻辑-这些是虚拟方法,例如,您可以为Foo类型重写Equals方法,但这对将解析为
对象的
IFoo a==IFoo b
没有帮助。ReferenceEquals(a,b)
基本上就是Aloraman所说的,但让我换一种方式来看看它是否变得更清晰。 当您将两个变量声明为IFoo,但随后将它们实例化为Foo对象时,变量声明将定义语法检查中可用的内容。变量声明是编译器可以看到的,但是直到执行才发生的实例化不是,因此编译器无法看到这两个Foo对象。因为IFoo没有并且不能有重载运算符==,编译器正确地将其视为错误。 当编译器试图找出用于某些操作的内容时,它无法知道这些对象实际上是Foo,因为在执行过程中会将这些IFoo变量指定为包含Foo对象。当您比较这两个IFoo变量时,编译器无法理解您是否真的想使用实现IFoo和重载==的一个类。 但是当变量被定义为Foo时,编译器非常清楚,在执行时,当它们被实例化时,它们必须被实例化为Foo类型,并且它确切地知道在哪里编译==运算符。
基本上,编译器在尝试编译该==运算符时,不会检查所有其他代码以查看如何实例化这两个操作数。如果它们被定义为IFoo,那是它能拥有的唯一信息。

基本上是Aloraman说的,但让我换一种方式来看看它是否变得更清晰。 当您将两个变量声明为IFoo,但随后将它们实例化为Foo对象时,变量声明将定义语法检查中可用的内容。变量声明是编译器可以看到的,但是直到执行才发生的实例化不是,因此编译器无法看到这两个Foo对象。因为IFoo没有并且不能有重载运算符==,编译器正确地将其视为错误。 当编译器试图找出用于某些操作的内容时,它无法知道这些对象实际上是Foo,因为在执行过程中会将这些IFoo变量指定为包含Foo对象。当您比较这两个IFoo变量时,编译器无法理解您是否真的想使用实现IFoo和重载==的一个类。 但是当变量被定义为Foo时,编译器非常清楚地知道