Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中的重载解析#_C#_Razor_Polymorphism_Overload Resolution - Fatal编程技术网

C# C语言中的重载解析#

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

在一个特定的案例中,我遇到了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 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表达式仅迭代特定类型,并将它们传递给相应的帮助器
  • 使用带有if语句的单个帮助器来确定类型并将工作传递给适当的方法
  • 想想你的实施策略是否真的是最好的
  • 在IEntity接口中放置一个渲染方法,并在迭代时调用它(我最不喜欢的选项)

  • 您可以尝试使用双重分派(即:访问者)模式来让您更接近。但是您仍然需要检查它是否不是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);
    }