简体   繁体   English

C#自定义一元运算符重载

[英]C# custom unary operators overloading

Does C# classes inherit custom operators from base classes? C#类是否从基类继承自定义运算符? I'm trying the following code: 我正在尝试以下代码:

class Person
{
    public int Age;

    public static Person operator ++(Person p)
    {
        p.Age++;
        return p;
    }
}

class Agent : Person {   }

static void Main(string[] args)
{
    Person p = new Person { Age = 23 };
    Console.WriteLine ( "Before increment : {0}" , p.Age );

    p++;
    Console.WriteLine("After increment : {0}", p.Age);

    Agent agent = new Agent { Age = 25 };
    Console.WriteLine("Before increment : {0}", agent.Age);

    agent++;
    Console.WriteLine("After increment : {0}", agent.Age);

}

The compiler told me that he cannot explicitly convert from Person to Agent. 编译器告诉我,他无法显式地从Person转换为Agent。

I tried : 我试过了 :

Agent agent = new Agent();
Person person = agent ++

But the same compiler message appear. 但是会出现相同的编译器消息。

The problem you are having is not based on whether or not the operator is inherited but due to the return type of the operator. 您遇到的问题不是基于运算符是否继承,而是由于运算符的返回类型。

However in the case of an assigning operator you will have an issue with the return type of the operator 但是,在分配运算符的情况下,运算符的返回类型会出现问题

The expression x++ is a short hand for 表达式x++是一个简写

x = x + 1

And in your case you are returning a Person and trying to assign that to an Agent . 在您的情况下,您将返回一个Person并尝试将其分配给Agent Written out that would be 写出来的

agent.Age++;
agent = (Person)agent; //the cast is implicit and a result of the return type

You can only assign to a more generalized type. 您只能分配更通用的类型。 So assigning an Agent to a Person would work which is why the compiler will allow the return type to be a specialization of the implementing type (as is the case below). 因此,将Agent分配给Person会起作用,这就是编译器允许返回类型成为实现类型的特化的原因(如下所示)。

You can accomplish what you are looking for with a bit of generics trickery 你可以通过一些泛型技巧来完成你正在寻找的东西

class Person<T> where T : Person<T>, new()
{
    public int Age;

    //taking advantage of the fact that the return type might be a specialization
    //of the type implementing the operator
    public static T operator ++(Person<T> p)
    {
        return new T { Age = p.Age + 1 };   
    }
}

class Agent : Person<Agent> { }

//Only required if Person should be usable on it's own
class Person : Person<Person> { }

The above operator constructs a new object which to me is inline with the contract of the ++ operator but also requires a default constructor, if you wish you can do it with a cast instead. 上面的运算符构造了一个新对象,它对我来说是与++运算符的契约内联,但是如果你希望你可以用一个强制转换来执行它,那么它也需要一个默认的构造函数。

public static T operator ++(Person<T> p)
{
    p.Age++;
    return (T)p;
}

Whether or not the operator is inherited is a matter of how you define inheritance. 是否继承运算符取决于您如何定义继承。

The C# specifications uses "inheritance" in a different manner than the CLI specifications . C#规范以与CLI规范不同的方式使用“继承”。 The way the C# specs uses inheritance is in the the context of operators and static methods incompatible with the CLI specification (Ie the C# spec contradict the CLI specifications and as such the platform C# runs on does not support the specifications) C#规范使用继承的方式是在运算符和静态方法的上下文中与CLI规范不兼容(即C#规范与CLI规范相矛盾,因此运行的C#平台不支持规范)

To out line why my money is on "operators are not inherited" is that they are syntax sugar for a static method. 为了说明我的钱为什么“运算符不是继承的”,它们是静态方法的语法糖。

[SpecialName]
public static T op_increment(Person<T> p)
{
    return new T { Age = p.Age + 1 };   
}

That's the implementation of a static method. 这是静态方法的实现。 According to the CLI specifications then static methods are not inherited: 根据CLI规范,静态方法不会被继承:

A derived object type inherits all of the instance and virtual methods of its base object type. 派生对象类型继承其基础对象类型的所有实例和虚方法。 It does not inherit constructors or static methods. 它不继承构造函数或静态方法。

below is an implementation of the ++ operator 下面是++运算符的实现

public static T operator ++(Person<T> p)
{
    return new T { Age = p.Age + 1 };   
}

The IL for both of these two implementations is identical 这两种实现的IL都是相同的

Operators are implemented as static and inheritance does not apply to static members. 运算符实现为静态,继承不适用于静态成员。

Some operators will work with derived types, some will not. 一些运算符将使用派生类型,有些则不会。 It is a matter of type conversion rules. 这是类型转换规则的问题。

But basically, Person p = ...; p++; 但基本上, Person p = ...; p++; Person p = ...; p++; is a very bad idea anyway. 反正是个坏主意。 When you use operator overloading where it is appropriate you won't run into problems like this. 当你在适当的地方使用运算符重载时,你不会遇到这样的问题。

Update: 更新:

Like other members, operators declared in a base class are inherited by derived classes. 与其他成员一样,在基类中声明的运算符由派生类继承。 Because operator declarations always require the class or struct in which the operator is declared to participate in the signature of the operator, it is not possible for an operator declared in a derived class to hide an operator declared in a base class. 因为运算符声明总是要求声明运算符的类或结构参与运算符的签名,所以在派生类中声明的运算符不可能隐藏在基类中声明的运算符。 Thus, the new modifier is never required, and therefore never permitted, in an operator declaration. 因此,在操作符声明中永远不需要new修饰符,因此从不允许。

Above quote from c# Language specification 以上引用来自c#语言规范


It does, Compiler checks to see any operator overloading defined in inheritance hierarchy. 它确实,编译器检查以查看继承层次结构中定义的任何运算符重载。 If found it uses that 如果发现它使用它

Consider the following code 请考虑以下代码

class Person
{
    public int Age;
    public static int operator +(Person p, Person p2)
    {
        return p.Age + p2.Age;
    }
}
class Agent : Person
{

}
static void Main()
{
    Person p = new Person { Age = 23 };
    Agent agent = new Agent { Age = 25 };

    int res = p + agent;//Result 48
    Console.WriteLine("Result is "+ res);
}

In your case compiler found ++ operator and tries to use it, but the problem is with return type. 在您的情况下编译器找到++运算符并尝试使用它,但问题是返回类型。 It returns base type, so it won't work. 它返回基类型,因此不起作用。 It can't be assigned to more derived type. 它不能分配给更多派生类型。

Here is the Demo 这是Demo

The ugly/pretty but not so generic solution: 丑陋/漂亮但不那么通用的解决方案:

class Agent : Person 
{
    public static Agent operator ++(Agent p)
    {
        p.Age++;
        return p;
    }
}

For this particular case, you could go with something like 对于这种特殊情况,你可以选择类似的东西

class Person
{
    public int Age;
    public static T IncrementAge<T>(T p) where T : Person
    {
        p.Age++;
        return p;
    }
}

Unfortunatelly, the following doesn't work: 不幸的是,以下情况不起作用:

    public static T operator ++<T>(T p) where T : Person
    {
        p.Age++;
        return p;
    }

The straight forward way would probably rather be this one, though: 然而,直截了当的方式可能是这个:

    public void IncrementAge()
    {
        Age++;
    }

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

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