【问题标题】:C# interface cannot contain operatorsC#接口不能包含操作符
【发布时间】:2011-09-30 01:01:42
【问题描述】:

谁能解释一下为什么C#接口不允许包含操作符?

谢谢。

【问题讨论】:

    标签: c# interface operators static-methods


    【解决方案1】:

    C#operators have to be static。根据定义,接口适用于实例。没有要求类型实现静态成员的机制。

    编辑:
    从 C# 8.0 开始,如您所见 here,现在可以在接口中定义本地方法并在接口本身内实现它们,例如允许创建方法重载,而无需实现也关心这些​​重载,因为它们可能只是为必须实现的重载提供附加参数。
    除此之外,您还可以在接口中定义运算符,但它们必须是静态的,因此必须在接口中实现。

    所以在 C# 8.0 中,这将打印“this works in C# 8”后跟“1”:

    interface ICanAdd
    {
        int Value { get; }
    
        public static int operator+ (ICanAdd lvalue, int rvalue)
        {
            Console.WriteLine("this works in C# 8");
            return lvalue.Value + rvalue;
        }
    }
    
    class Add : ICanAdd
    {
        public int Value => 0;
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            ICanAdd foo = new Add();
            var x = foo + 1;
            Console.WriteLine(x);
        }
    }
    

    编辑 2020-01-23

    您不能在接口中添加转换、相等或不等运算符,否则您会遇到以下错误:

    CS0567 C# 接口不能包含转换、相等或不等运算符

    【讨论】:

    • @pickles - 语言/编译器无法创建这样的构造并没有硬性原因(我认为实际上可能有一些可以做到 - 德尔福也许,它可以在 C++ 中使用模板(T::Method()))在某种程度上被模仿(至少是静态虚拟方法) - C# 选择不这样做。
    • 这篇文章的第二个答案有一些关于为什么 C# 没有这个的评论。 stackoverflow.com/questions/259026/…
    • 抱歉恢复一个旧线程,但由于索引括号运算符/“属性”不是静态的,它们可以在界面中使用。
    • @GregKramida C# 中的不同之处在于,索引器在技术上并不是 C++ 中的运算符。它是语言中的语法糖,它可以归结为 IL 中的实例方法 get_Item。在语法规范中,索引器和运算符分别声明且不同。 msdn.microsoft.com/en-us/library/aa664812(v=vs.71).aspx
    • 感谢@DavideCannizzo 指出这在 C# 8 中发生了变化
    【解决方案2】:

    您不能在接口上定义运算符,因为一个类可以实现多个接口。想象一下,如果这个代码是可能的:

    static class Fooness {
      public static operator==(IFoo l, IFoo r) { ... }
    }
    static class Barness {
      public static operator==(IBar l, IBar r) { ... }
    }
    
    public class Foobar : IFoo, IBar { ... }
    

    如果在 Foobar 的实例上使用,哪个 == 实现应该占上风? (在你回答之前,想象一下如果 IFoo/Fooness 来自一个 DLL 而 IBar/Barness 来自另一个)。

    即使你能以某种方式解决这种模棱两可的问题,我们也应该问问自己这是否是一个好主意。我希望以上内容表明使用 operator== 这是一个非常糟糕的主意。 per-interface == 运算符的作者假定,在进行比较时,对象的唯一重要方面是接口所包含的方面。有时这可能是正确的,但通常情况并非如此。

    这就是为什么只在密封类上使用运算符是谨慎的。只有这样,您才能确定您的操作员对对象有足够的了解才能正常工作。

    【讨论】:

      【解决方案3】:

      如果您的方法无法在接口上正确实现,您可以调用将被派生类覆盖的 self 方法:

      public interface INotification
      {
              INotification Combine(INotification b);
              
              public static INotification operator +(INotification a, INotification b)
              {
                  return a.Combine(b);
              }
      }
      

      派生类:

      public class Notification : INotification
      {
      
              public INotification Combine(INotification b)
              {
                  _events.AddRange(b.Events);
                  _logs.AddRange(b.Logs);
                  ValidationResult.Errors.AddRange(b.GetValidationErrors());
      
                  return this;
              }
      
              public static Notification operator +(Notification a, Notification b)
              {
                  a._events.AddRange(b.Events);
                  a._logs.AddRange(b.Logs);
                  a.ValidationResult += b.ValidationResult;
      
                  return a;
              }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-03-01
        • 2011-01-03
        • 2011-01-08
        • 1970-01-01
        • 2021-12-30
        • 2021-11-20
        相关资源
        最近更新 更多