我正在用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();
}
}
虽然这在技术上意味着我不再有问题,但我仍然很好奇为什么会这样。