简体   繁体   English

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

[英]Operator overloading on class that implements interface

Suppose I have an interface IFoo, and a class Foo that implements IFoo. 假设我有一个接口IFoo和一个实现IFoo的类Foo。 I want to define my own logic for determining if 2 instances of Foo are equal based on the data they contain and overload the == & != operators for ease of use when working with Foo. 我想定义自己的逻辑,根据它们包含的数据确定2个Foo实例是否相等,并重载==和!=运算符,以便在使用Foo时易于使用。

If I have 2 instances of Foo, both stored as Foo, then this works fine. 如果我有2个Foo实例,都存储为Foo,则可以正常工作。 However, if I have 2 instances both stored as IFoo, suddenly my overloaded operators aren't being called anymore. 但是,如果我有两个实例都存储为IFoo,则突然不再调用我的重载运算符。 Furthermore, since I can't define an operator on my IFoo interface and at least one of the arguments in my Foo operator overload must be of type Foo, I can't see that there's any way I can successfully overload the operator on my type. 此外,由于我无法在IFoo接口上定义运算符,并且Foo运算符重载中的至少一个参数必须为Foo类型,因此我看不到有任何方法可以成功使我的类型重载该运算符。 Is this correct? 这个对吗?

Also, can anyone clear up why this is happening? 另外,任何人都可以弄清为什么会这样吗? Normally I'd expect that the fact my Foos are being stored as IFoos should be irrelevant in determining which equality function gets called, since fundamentally they're still Foos! 通常,我希望将我的Foos存储为IFoos与确定调用哪个相等函数无关,因为从根本上说,它们仍然是Foos!

Any help really appreciated 任何帮助真的很感激

Thanks 谢谢

Edit: Ok, since there seems to be a bit of confusion of what I mean, here's an example which should hopefully clarify a bit: 编辑:好的,因为我的意思似乎有些混乱,所以这里有一个例子,希望可以澄清一下:

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

Operator overloading exists in compile-time only, after compilation it is just a call to a specific static method with well-known name. 运算符重载仅在编译时存在,编译后仅是对具有已知名称的特定静态方法的调用。

C# compiler recognizes operator overloading for Foo and replaces a == b with Foo.op_Equality(a,b) . C#编译器可以识别Foo运算符重载,并用Foo.op_Equality(a,b)替换a == b That means there is non-virtual static method op_Equality in class Foo after compilation. 这意味着编译后,类Foo中存在非虚拟静态方法op_Equality Therefore it is not possible to overload operators for interfaces - interfaces cannot have static methods. 因此,不可能重载接口的运算符-接口不能具有静态方法。 Moreover, operator methods are non virtual , that means actual method is resolved from types of variables, not types of values, so compiler will look for possible operator overloading based on variable types of a and b , if both of them are IFoo , then it can only look for op_Equality in IFoo type - which cannot have it. 而且,运算符方法是非虚拟的 ,这意味着实际方法是从变量类型而不是值的类型解析的,因此编译器将基于ab变量类型寻找可能的运算符重载,如果它们都是IFoo ,则它将只能在IFoo类型中查找op_Equality不能拥有它。

You can provide custom logic only for methods which are resolved based on types of values - those are virtual methods, eg you can override Equals method for Foo type, but it won't help you with IFoo a == IFoo b , which will be resolved to Object.ReferenceEquals(a,b) 您只能为基于值类型解析的方法提供自定义逻辑-这些是虚拟方法,例如,您可以为Foo类型覆盖Equals方法,但是如果使用IFoo a == IFoo b无济于事。解析为Object.ReferenceEquals(a,b)

Basically what Aloraman said, but let me put it another way to see if it gets clearer. 基本上是Aloraman所说的,但是让我用另一种方式看一下它是否变得更加清晰。

When you have two variables declared as IFoo, but then you instantiate them as Foo objects, the variable declaration defines what is available at the syntax check. 当您有两个声明为IFoo的变量,但是将它们实例化为Foo对象时,变量声明定义了语法检查中可用的变量。 The variable declaration is there for the compiler to see, but the instantiation, which does not occur until execution, is not, so the compiler has no way to see that those are really two Foo objects. 变量声明在那里供编译器查看,但是实例化直到执行才发生,实例化就不会出现,因此编译器无法看到它们实际上是两个Foo对象。 Because IFoo does not have, and cannot have an overloaded operator ==, the compiler rightly sees that as an error. 因为IFoo没有并且不能有重载的运算符==,所以编译器正确地将其视为错误。

When the compiler tries to figure out what to use for some operation, it cannot know that those objects are really Foo, because assigning those IFoo variables to contain Foo objects happens during execution. 当编译器试图弄清楚用于某种操作的内容时,它不能知道那些对象实际上是Foo,因为分配这些IFoo变量以包含Foo对象是在执行期间发生的。 The compiler cannot read your mind that you really mean to use the one class that implements IFoo and overloads == when you compare those twoo IFoo variables. 当您比较这两个IFoo变量时,编译器无法理解您的真正意图是使用实现IFoo和重载==的一个类。

But when the variables are defined as Foo, the compiler knows perfectly well that at execution, when they get instantiated, they will have to be instantiated as Foo type, and it knows exactly where to go to compile that == operator. 但是,当将变量定义为Foo时,编译器就完全知道,在执行时,实例化它们时,必须将它们实例化为Foo类型,并且它确切地知道在哪里编译==运算符。

Basically, the compiler, when it tries to compile that == operator, does NOT go over all your other code to see how you instantiated the two operands. 基本上,编译器在尝试编译==运算符时,不会遍历所有其他代码来查看如何实例化这两个操作数。 If they are defined as IFoo, that is the only information it can have. 如果将它们定义为IFoo,则它将是仅有的信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM