【问题标题】:Why is a method of a interface not found by C# dynamic on internal classes?为什么 C# 动态在内部类上找不到接口的方法?
【发布时间】:2020-12-27 15:14:06
【问题描述】:

我尝试使用dynamic 访问位于另一个程序集中的类的方法。这些类是internal,由返回public 接口的构建器创建。由于某种原因dynamic 无法调用接口上定义的方法。我可以使用“经典”反射来运行代码,但我不明白为什么它不适用于 dynamic

我知道dynamic 不使用内部类的方法,但这里我们有一个公共接口。那么请有人解释一下为什么dynamic 在下面的示例中抛出RuntimeBinderException

    namespace SandboxLib  // located in SandboxLib.dll
    {
        public class InternalBuilder
        {
            public static IInterface Build()
            {
                return new InternalClass();
            }
        }

        public interface IInterface
        {
            void IfMethod();
        }
        
        internal class InternalClass : IInterface
        {
            public void IfMethod() { }
        }
    }

    namespace Sandbox  // located in Sandbox.dll
    {
        public class Program
        {
            static void Main(string[] args)
            {
                var inst = InternalBuilder.Build();
                dynamic dynInst = inst;

                inst.IfMethod();     // ok
                dynInst.IfMethod();  // Unhandled exception. Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'IfMethod'
            }
        }
    }

【问题讨论】:

  • 它似乎并不关心接口,并试图访问实例化的内部类方法。我不得不想知道你为什么一开始就处于这种情况。 dynamic 任何事情通常会导致比在最好的日子里解决的问题多 2 个问题
  • 该应用程序是一个简单的检查工具,用于显示内部类提供的值。由于这些类是泛型类并且方法是async 方法,因此使用反射有点痛苦。在给定的位置,我不知道内部类有什么泛型类型,因此需要大量代码来提取值。但你是对的,通常我会尽量避免使用 dynamic 并尽可能选择显式类型。
  • 不幸的是,这种情况是不允许的,反思也许是你唯一的选择。

标签: c# dynamic reflection


【解决方案1】:

C# 标准中描述了此行为:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#dynamic-binding

在“成员查找”下它指出:

成员查找不仅考虑成员的名称,还考虑 成员拥有的类型参数的数量以及成员是否是 可访问

由于dynamic解析找到的成员IfMethod()internal,按照规范调用会失败。

【讨论】:

  • 但它似乎有点受限,它不查找接口成员。在编译时它正确解析为接口,为什么它在运行时不做同样的事情?
  • @InBetween 好吧,这将是一个需要向语言设计者提出的问题,但规范对此非常清楚。
  • 我想你也可以看看 12.3 Static and Dynamic Binding of the ecma specs “但是,如果一个表达式是一个动态表达式(即有类型动态)这表明它参与的任何绑定都应该基于它的运行时类型,而不是它在编译时的类型。因此,这种操作的绑定被推迟到程序运行期间要执行该操作的时间。这称为动态绑定。
  • 我仍然不认为这是一个正当的理由。你告诉我 dynamic 本质上通过接口使多态性无效......这没有多大意义。我已经构建了一个简单的示例,其中 dynamic 完美地绑定到暴露不可访问类型的接口。检查here。它不一样,但如果你的推理是正确的,或者我在这里误解了一些东西,这也应该失败。
  • @MichaelRandall 啊,你是对的!它绑定到Foo.Frob,而不是IFoo.FrobThis 实际上也失败了,这与 OP 完全相同。哇,不知道这个,我发现这是一个非常意想不到的动态限制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-13
  • 2016-10-06
  • 2018-09-20
  • 1970-01-01
相关资源
最近更新 更多