.net c#标记为过时的接口方法在实现时不会从编译器发出消息

Interface method marked as Obsolete does not issue a message from the compiler when implemented
2021-09-15
  •  译文(汉语)
  •  原文(英语)

考虑这个例子

    public interface IAnimal
    {
        [Obsolete("Animals can't eat anymore", true)]
        void Eat();
    }

    public class Animal : IAnimal
    {
        public void Eat()
        {
            Console.WriteLine("Hello");
        }
    }

我有一个过时的方法IAnimal接口.类动物实现该接口.

稍后,我这样调用Eat方法:

var animal = new Animal();
animal.Eat();

编译器不会编译失败(我已将Obsolete标记为给出错误而不是警告).程序将编译,并且该方法也将被正确调用.

据我所见,这是来自编译器的错误.我有什么想念的吗?

注意:我正在使用VS2010

速聊1:
这不是编译器错误.
速聊2:
:如果我已将过时标记为警告,则编译器是否应向实施该警告的人提供警告?我了解过时的标记可能会导致错误
速聊3:
这也不是编译器错误.您没有标记为Animal.Eat已过时,而是标记为IAnimal.Eat已过时.您使用了Animal.Eat,可能不会过时.
速聊4:
问题是使用var而不是将对象类型显式声明为IAnimal.感谢@DocMax提供清晰的解释.显式声明类型确实会导致预期的警告.
解决过程1

您仅将IAnimal.Eat标记为过时,而不是Animal.Eat.该变种关键字解析为动物,所以,当你调用animal.Eat,你不指责标记为过时的任何方法.

要解决此问题,可以将var显式更改为IAnimal,或者更好的是,将Animal.Eat也标记为过时的:

    public interface IAnimal
    {
        [Obsolete("Animals can't eat anymore", true)]
        void Eat();
    }

    public class Animal : IAnimal
    {
        [Obsolete("Animals can't eat anymore", true)]
        public void Eat()
        {
            Console.WriteLine("Hello");
        }
    }
解决过程2

它看起来像行为,是因为你var animalAnimal其中的Eat方法还没有过时.如果您这样做:

IAnimal animal = new Animal();
animal.Eat();

您应该看到预期的警告/错误.

解决过程3

编译器不会针对接口中的过时方法发出警告,而只会针对方法调用发出警告.这样做有充分的理由:

您可能总是为您的方法命名 Eat

始终允许您实现一个方法Eat,Animal无论该方法是否也存在于接口之一中并标记为已过时.例如,如果允许这样做:

public class Animal
{
    public void Eat() { /* ... */ }
}

为什么不允许这样做:

public class Animal : IAnimal
{
    public void Eat() { /* ... */ }
}

必须实现所有接口方法

您需要实现接口中存在的所有方法.您不能跳过它们中的任何一个,即使它们已过时也是如此.

例如,如果您没有添加Eat,那么您将不会实现该接口的所有成员,并且会遇到其他错误:

public class Animal : IAnimal
{
    // No Eat()
}

"动物"未实现接口成员"IAnimal.Eat()"

速聊1:
第二个原因是大原因.接口的创建者可能希望劝阻人们不要使用特定的方法,但是系统将坚持要求声称实现接口的每个类都必须实现每个成员,无论是否有人使用它.
速聊2:
第二个原因在这里没有任何意义.即使必须实现该方法,也应向调用过时方法的代码发出过时警告.实现类上的方法可以只是无操作方法,或者在调用时抛出NotImplementedException.

Consider this example

    public interface IAnimal
    {
        [Obsolete("Animals can't eat anymore", true)]
        void Eat();
    }

    public class Animal : IAnimal
    {
        public void Eat()
        {
            Console.WriteLine("Hello");
        }
    }

I have an interface IAnimal with an obsoleted method. The Class Animal implements that interface.

Later on, i call the Eat method as such:

var animal = new Animal();
animal.Eat();

The compiler does not fail to compile (i have Obsolete marked to give an error instead of an warning). The program compiles and the method is invoked with no errors, as well.

As far as i can see this is a bug from the compiler. Am i missing anything?

Note: i am using VS2010

Talk1:
This is not a compiler bug.
Talk2:
: if i had marked obsolete as warning shouldn't the compiler provide a warning to whoever implements it? I understand marking obsolete to give an error can be a corner case
Talk3:
That's not a compiler bug either. You didn't mark Animal.Eat obsolete, you marked IAnimal.Eat obsolete. You used Animal.Eat, which might not be obsolete.
Talk4:
The problem is the use of var instead of explicitly declaring the object type as IAnimal. Thanks to @DocMax for providing a clear explanation. Declaring the type explicitly does result in the expected warning.
Solutions1

You've only marked IAnimal.Eat as obsolete, not Animal.Eat. The var keyword resolves to Animal, and so when you call animal.Eat, you're not calling into any method marked as Obsolete.

To fix, either explicitly change var to IAnimal, or better still, mark Animal.Eat as obsolete as well:

    public interface IAnimal
    {
        [Obsolete("Animals can't eat anymore", true)]
        void Eat();
    }

    public class Animal : IAnimal
    {
        [Obsolete("Animals can't eat anymore", true)]
        public void Eat()
        {
            Console.WriteLine("Hello");
        }
    }
Solutions2

It looks like the behavior is because your var animal is an Animal in which the Eat method is not obsolete. If you did:

IAnimal animal = new Animal();
animal.Eat();

you should see the warning/error that you expect.

Solutions3

The compiler won't warn for obsolete methods from interfaces, only for method calls. There are good reasons for this:

You may always name your method Eat

You are always allowed to implement a method Eat on Animal regardless of whether it is also present in one of the interfaces and marked obsolete. For example, if this is allowed:

public class Animal
{
    public void Eat() { /* ... */ }
}

Why wouldn't this be allowed:

public class Animal : IAnimal
{
    public void Eat() { /* ... */ }
}

All interface methods must be implemented

You are required to implement all methods present in an interface. You can't skip any of them, not even when they are obsolete.

For example, if you didn't add Eat, you wouldn't have implemented all members of the interface and you'd get other errors:

public class Animal : IAnimal
{
    // No Eat()
}

'Animal' does not implement interface member 'IAnimal.Eat()'

Talk1:
The second reason is the big one. The author of an interface may wish to discourage people from using a particular method, but the system's going to insist that every class that claims to implement an interface must implement every member whether or not anyone uses it.
Talk2:
The second reason doesn't make any sense here. Even if the method must be implemented, the deprecation warning should be issued to code calling the deprecated method. The method on the implementation class could simply be a no-op method, or throw a NotImplementedException when called.
转载于:https://stackoverflow.com/questions/15560445/interface-method-marked-as-obsolete-does-not-issue-a-message-from-the-compiler-w

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入