【问题标题】:How to solve this c# syntax puzzle?如何解决这个 c# 语法难题?
【发布时间】:2016-01-29 19:37:06
【问题描述】:

谁能给我以下代码难题的解决方案? 给出了一个解决方案,但可能不止一个解决方案。

// this code compiles
IAnimal animal= new Dog();
animal.Eat();

// this code doesn't compile
Dog animal = new Dog();
animal.Eat();

类定义应该如何使上述代码块在不同的范围内编译(第一个)而不编译(第二个)?

【问题讨论】:

  • 这段代码无法编译 - 什么是编译器错误?
  • 如果 IAnimal 可以吃 () 并且 Dog 是 IAnimal,那么根据定义,Dog 可以吃 ()。
  • @Domysee - 他们并不是说他们的代码无法编译 - 他们是在询问如何编写代码以使上述两行产生所需的编译/非编译行为。
  • @pstrjds 哦,对了。感谢您的澄清

标签: c# .net logic


【解决方案1】:

您可以通过使用显式接口实现来实现这一点:

class Dog : IAnimal {
    void IAnimal.Eat(){
        //do stuff
    }
}

相对于隐式接口实现:

class Dog : IAnimal {
    public void Eat(){
        //do stuff
    }
}

【讨论】:

    【解决方案2】:
    public interface IAnimal
    {
        void Eat();
    }
    
    public class Dog : IAnimal
    {
        void IAnimal.Eat() { }
    }
    
    
    
    IAnimal animal = new Dog();
    animal.Eat(); // <---- OK
    
    Dog animal2 = new Dog();
    animal2.Eat(); // <---- COMPILE ERROR
    

    【讨论】:

    • 对这个问题的答案的一些解释将有助于 OP 理解这个答案。
    【解决方案3】:

    第二行的错误是因为Dog显式实现了IAnimal接口这样的:

    class Dog : IAnimal
    {
        void IAnimal.Eat()
        {
            throw new NotImplementedException();
        }
    }
    

    在这种情况下,您会在第二行出现编译错误,因为您无法调用 Eat,除非您正在使用 IAnimal 的实例,因为它本质上是 Dog 中的私有方法。

    要修复错误,您需要将实例转换回IAnimal,就像我在上面向您展示的那样,或者您可以隐式实现这样的接口:

    class Dog : IAnimal
    {
        public void Eat()
        {
            throw new NotImplementedException();
        }
    }
    

    【讨论】:

    • OP 询问的是如何生成可以做到这一点的代码,而不是我如何调用代码以便它可以工作。他们没有任何代码-请注意问题中的这一行-“类定义应如何使上述代码块在不同的范围内编译(第一个)和不编译(第二个)”
    【解决方案4】:

    其他答案中已经提供了明显的解决方案(IAnimal 是接口,Dog 是显式实现该接口的类)。

    这里有一些我能想到的其他方法。

    所有这些都基于IAnimal 是一个像这样的(命名不佳的)类

    public class IAnimal
    {
        public void Eat() { }
    }
    

    (A) 基于类定义隐式转换运算符的解决方案(请注意,禁止定义从类到接口的转换,这就是为什么IAnimal 成为类/结构很重要)

    public class Dog
    {
        public static implicit operator IAnimal(Dog dog) { return new IAnimal(); }
    }
    

    在第二个 sn-p 中导致以下编译错误:

    错误 CS1061:“Dog”不包含“Eat”的定义,并且找不到接受“Dog”类型的第一个参数的扩展方法“Eat”(您是否缺少 using 指令或程序集引用?)

    (B) 基于基本方法隐藏的解决方案。虽然在 C# 中我们不能通过在派生类中提供另一个具有不同签名的方法来隐藏基方法(因为它将被视为 overload),但我们可以通过使用 field 来做到这一点propertyevent 具有不兼容的签名。

    例如

    public class Dog : IAnimal
    {
        new public event Action Eat;
    }
    

    生成

    错误 CS0070:事件“Dog.Eat”只能出现在 += 或 -= 的左侧(在“Dog”类型中使用时除外)

    public class Dog : IAnimal
    {
        new public Action<int> Eat;
    }
    

    生成

    错误 CS7036:没有给出与“Action”的所需形参“obj”相对应的参数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-16
      • 2012-01-25
      • 2023-03-27
      • 1970-01-01
      • 2016-06-02
      • 2017-02-28
      • 1970-01-01
      相关资源
      最近更新 更多