C# C语言中的重载解析#
在一个特定的案例中,我遇到了C#中重载解析的问题。在我的Razor文件中,我有以下内容:C# C语言中的重载解析#,c#,razor,polymorphism,overload-resolution,C#,Razor,Polymorphism,Overload Resolution,在一个特定的案例中,我遇到了C#中重载解析的问题。在我的Razor文件中,我有以下内容: @foreach (var result in Model.Result) { @SearchResult(result) } @helper SearchResult(IEntity entity) { <p>A normal thing</p> } @helper SearchResult(IPhoto photo) { <p>A phot
@foreach (var result in Model.Result)
{
@SearchResult(result)
}
@helper SearchResult(IEntity entity)
{
<p>A normal thing</p>
}
@helper SearchResult(IPhoto photo)
{
<p>A photo! Its title is @photo.Title</p>
}
正在传递的实际实例是Photo
SearchResult(IEntity)
在应该调用SearchResult(IPhoto)
时(或者不管IEntity派生的实例的最具体的重载)为每个实例调用。我怎么能做我想做的事而不用求助于这个
if (result is IXXX) { SearchResultXXX((IXXX)result) }
else if (result is IYYY) { SearchResultYYY((IYYY)result) }
...
属性的类型是什么
Model.Result
?我的猜测是这是entity
将调用哪个重载的决定是在编译时而不是运行时进行的,因此无论实例的类型是什么,它都将始终调用SearchResult(entity entity)
方法
更新
这是该问题的一种可能解决方案:
@foreach (var result in Model.Result)
{
@if(result is IPhoto)
{
@SearchResult(result as IPhoto)
}
else
{
@SearchResult(result)
}
}
您遇到这个问题是因为您的接口实现。像
IPhoto
实现了icontetitem
,它实现了IEntity
。这篇文章对重载解析提供了一个很好的解释,但总而言之:重载忽略了在决定调用哪个方法时可能不正确的任何方法。从上的Microsoft规范:
重载解析是一种编译时机制,用于选择最佳的
给定参数列表和一组
候选职能成员。重载解析选择函数
要在C#中的以下不同上下文中调用的成员:
调用调用表达式中命名的方法(第节)
7.5.5). 调用对象创建表达式中命名的实例构造函数(第7.5.10.1节)。调用
通过元素访问的索引器访问器(第7.5.6节)。调用
表达式中引用的预定义或用户定义运算符的
(第7.2.3节和第7.2.4节)。这些上下文中的每一个都定义了
候选函数成员集及其自身的参数列表
独特的方式,如上所列章节中详细描述。对于
例如,方法调用的候选集不包含
包括标记为override(第7.3节)的方法和基础中的方法
如果派生类中的任何方法是
适用(第7.5.5.1节)
完成候选函数成员和参数列表后
确定后,最佳功能成员的选择在
所有情况:
给定一组适用的候选函数成员,最佳
该集合中的函数成员位于。如果集合只包含一个
函数成员,则该函数成员是最佳函数
成员。否则,最好的功能成员是一个功能成员
这比所有其他函数成员在
给定参数列表,前提是将每个函数成员与
使用第7.4.2.2节规则的所有其他职能成员。如果
没有一个函数成员比所有其他函数成员都好
函数成员,则函数成员调用不明确且
发生编译时错误。以下各节定义了确切的
适用功能成员和更好功能术语的含义
成员
下面是前面提到的一些例子来说明
熟悉重载的任何人都会意识到,在下面的示例中,调用行Foo(“text”)
时将使用static void Foo(字符串y)
class Test
{
static void Foo(int x)
{
Console.WriteLine("Foo(int x)");
}
static void Foo(string y)
{
Console.WriteLine("Foo(string y)");
}
static void Main()
{
Foo("text");
}
}
这里有一个更复杂的问题,但更好的问题更类似于您的问题。编译器将调用Foo(intx)
,因为它会寻找更好的函数成员规则,这些规则会查看(除其他外)从每个参数到相应参数类型(第一个方法是int,第二个方法是double)所涉及的转换
所有这些都解释了,你的情况是,IEntity
是一张照片的最佳转换,而不考虑IPhoto
过载的事实。这与Razor@helper语法无关。为了说明这一点,下面的扩展方法也存在同样的“问题”
public static class SearchHelper
{
public static MvcHtmlString SearchResult(this HtmlHelper helper,
IEntity entity)
{
return new MvcHtmlString("A normal thing");
}
public static MvcHtmlString SearchResult(this HtmlHelper helper,
IPhoto photo)
{
return new MvcHtmlString("A photo!");
}
}
最后,我在这里介绍的是更简单的情况——泛型、可选参数、继承层次结构等导致的重载解析中还有其他奇怪之处。因此,在我看来,尽管如此,您仍有一些选择:
.Where
lambda表达式仅迭代特定类型,并将它们传递给相应的帮助器您可以尝试使用双重分派(即:访问者)模式来让您更接近。但是您仍然需要检查它是否不是IEntity(除非您可以控制IEntity接口)
接口IContentItem{
无效接受(IContentVisitor访客);
}
班级照片:IPhoto{
无效接受(IContentVisitor访问者){visitor.Visit(this);}
}
接口IContentVisitor{
T参观(IPhoto照片);
T访问(独立实体);
}
类内容访问者:IContentVisitor{
字符串访问(IPhoto照片){return“一件正常的事情”;}
字符串访问(IEntity实体){return“一件普通的事情”;}
}
var visitor=newcontentvisitor();
@foreach(Model.result中的var结果)
{
如果(结果为IContentItem)
结果:接受(访客);
else//假设结果是一致的
访客访问(结果);
}
“我该如何做我想做的事…”你想做什么?这里的问题是,IPhoto
继承了
class Test
{
static void Foo(int x)
{
Console.WriteLine("Foo(int x)");
}
static void Foo(double y)
{
Console.WriteLine("Foo(double y)");
}
static void Main()
{
Foo(10);
}
}
public static class SearchHelper
{
public static MvcHtmlString SearchResult(this HtmlHelper helper,
IEntity entity)
{
return new MvcHtmlString("A normal thing");
}
public static MvcHtmlString SearchResult(this HtmlHelper helper,
IPhoto photo)
{
return new MvcHtmlString("A photo!");
}
}
interface IContentItem {
void Accept(IContentVisitor visitor);
}
class Photo : IPhoto {
void Accept(IContentVisitor visitor) { visitor.Visit(this); }
}
interface IContentVisitor<T>{
T Visit(IPhoto photo);
T Visit(IEntity entity);
}
class ContentVisitor : IContentVisitor<string>{
string Visit(IPhoto photo) { return "<p>A normal thing</p>"; }
string Visit(IEntity entity) { return "<p>A normal thing</p>"; }
}
var visitor = new ContentVisitor();
@foreach (var result in Model.Result)
{
if(result is IContentItem)
result.Accept(visitor);
else //assuming result is IEntity
visitor.Visit(result);
}