【问题标题】:Why do I need to cast 'this' to an interface with a default implementation in C# 8.0 when I call it in the class derived form that interface?为什么我需要将“this”转换为具有 C# 8.0 中默认实现的接口,当我在该接口的类派生形式中调用它时?
【发布时间】:2020-08-14 12:51:29
【问题描述】:

我在带有 C# 8 的 .NET Core 3.1 中有这个简单的控制台程序:

using System;

namespace ConsoleApp34
{

    public interface ITest
    {
        public void test()
        {
            Console.WriteLine("Bye World!");

        }
    }

    public class Test : ITest
    {
        public void CallDefault()
        {
            ((ITest)(this)).test();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            var t = new Test();
            t.CallDefault();

        }
    }
}

我不明白为什么((ITest)(this)).test(); 行中需要演员表

Test 直接派生自 ITest,因此,根据定义,'this' IS ITest

谢谢。

【问题讨论】:

    标签: c# .net-core c#-8.0 default-interface-member


    【解决方案1】:

    默认接口实现的工作方式与显式实现类似:它们只能通过接口类型调用,而不能通过实现类型调用。

    要理解为什么会这样,想象一下Test 实现了两个具有相同方法签名的接口;如果没有演员表,将使用哪个?

    public interface ITest2
    {
        public void test()
        {
            Console.WriteLine("Hello World!");
        }
    }
    
    public class Test : ITest, ITest2
    {
        public void CallDefault()
        {
            test(); // Do we use ITest.test() or ITest2.test()?
        }
    }
    

    【讨论】:

    • 我的示例中不存在这种歧义。但对于你的例子,像'ITest.test();'这样的语法和'ITest2.test();'将消除歧义,而编译器可以检查错误。如果您使用强制转换,您可以尝试强制转换为类不继承的接口,从而创建运行时错误而不是编译时错误。..
    • @user1777224 语法ITest.test(); 已用于静态接口方法。尽管在您的具体示例中没有歧义,但编译器需要能够解释 每个 情况,包括许多边缘情况。直接调用test() 唯一安全的情况是只实现了1 个接口;在 .NET 中,这就是为什么类只允许单继承,而接口应该总是允许共存而不用担心冲突。
    【解决方案2】:

    这种行为是documented here

    从 C# 8.0 开始,您可以为接口中声明的成员定义实现。如果类从接口继承方法实现,则只能通过接口类型的引用访问该方法。继承的成员不会作为公共接口的一部分出现。以下示例定义了接口方法的默认实现:

    public interface IControl
    {
        void Paint() => Console.WriteLine("Default Paint method");
    }
    public class SampleClass : IControl
    {
        // Paint() is inherited from IControl.
    }
    

    以下示例调用默认实现:

    var sample = new SampleClass();
    //sample.Paint();// "Paint" isn't accessible.
    var control = sample as IControl;
    control.Paint();
    

    任何实现 IControl 接口的类都可以覆盖默认的 Paint 方法,可以是公共方法,也可以是显式接口实现。

    【讨论】:

    • 全部正确,但我不确定这是否解释了为什么会出现这种情况,这正是 OP 要求的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 2013-09-06
    • 2013-09-30
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    • 1970-01-01
    相关资源
    最近更新 更多