为什么在尝试调用具有动态参数的内部方法时抛出RuntimeBinderException?

时间:2016-11-21 22:09:33

标签: c# exception dynamic-typing

我正在用C#开发一个应用程序,在我的一个项目中我定义了一个接口:

internal interface IArticleResolver
{
    string Resolve(string article, dynamic context);

    void TestMethod();
}

在同一个项目中,我实现了如下界面:

internal class ArticleResolver : IArticleResolver
{
    public string Resolve(string article, dynamic context)
    {
        throw new NotImplementedException();
    }

    public void TestMethod()
    {
        // Pass through.
    }
}

该项目将其内部结构暴露给同一解决方案中的单元测试库。在该单元测试库中,我定义了以下测试:

[Theory]
[MemberData(nameof(Examples))]
internal void Article_Resolver_Should_Resolve_Article_From_Context_As_Expected(
    string unresolvedArticle,
    dynamic context,
    string expectedResolvedArticle)
{
    // WHEN we resolve the article using the given context.
    this.articleResolver.TestMethod();
    string actualResolvedArticle = this.articleResolver.Resolve(unresolvedArticle, context);

    // THEN the article should have been resolved as expected.
    actualResolvedArticle.ShouldBe(expectedResolvedArticle);
}

我发现this.articleResolver.TestMethod()可以毫无问题地被调用,正如我所期望的那样。但是,this.articleResolver.Resolve(...)会导致RuntimeBindingException被抛出,即使它处于相同的可访问性级别。完整的信息是:

  

'Mofichan.Library.IArticleResolver.Resolve(string,object)'由于其保护级别而无法访问

这个方法唯一特别之处在于它接受一个动态参数,我假设它是原因。如果我公开IArticleResolver,我会发现NotImplementedException会被抛出(正如预期的那样)。

动态属性是否会导致此行为?如果是这样,有没有办法在不使接口或实现类公开的情况下测试此代码?

修改1

如果它是有用的信息,我正在针对.NET Core SDK 1.1开发此应用程序,现在我正在Windows 10机器上测试它。

修改2

我做了一些进一步的测试,我发现了一些有趣的结果。如果您将具有静态类型RuntimeBinderException的对象传递给方法,则似乎仅抛出dynamic

// WHEN we resolve the article using the given context.
this.articleResolver.TestMethod();
this.articleResolver.Resolve(unresolvedArticle, "foo"); // NotImplementedException
this.articleResolver.Resolve(unresolvedArticle, new ExpandoObject()); // NotImplementedException
this.articleResolver.Resolve(unresolvedArticle, (dynamic)new ExpandoObject()); // RuntimeBinderException
string actualResolvedArticle = this.articleResolver.Resolve(unresolvedArticle, context);

编辑3

在将单元测试方法的RuntimeBinderException参数更改为其实际静态类型(context)后,我不再获得ExpandoObject

[Theory]
[MemberData(nameof(Examples))]
internal void Article_Resolver_Should_Resolve_Article_From_Context_As_Expected(
    string unresolvedArticle,
    ExpandoObject context,
    string expectedResolvedArticle)
{
    // WHEN we resolve the article using the given context.
    string actualResolvedArticle = this.articleResolver.Resolve(unresolvedArticle, context);

    // THEN the article should have been resolved as expected.
    actualResolvedArticle.ShouldBe(expectedResolvedArticle);
}

测试中的方法本身保持不变:

internal class ArticleResolver : IArticleResolver
{
    public string Resolve(string article, dynamic context)
    {
        throw new NotImplementedException();
    }
}

虽然这在技术上意味着我不再有问题,但我仍然很好奇为什么会这样。

0 个答案:

没有答案