繁体   English   中英

在重载方法中使用泛型类型

[英]Use of generic types in overloaded methods

我有一个通用的方法:

public bool DoSomething<T>(T item) where T: IBase
{
    return DoSomethingSpecific(item);
}

public bool DoSomethingSpecific(IBase item)
{
    return true;
}

public bool DoSomethingSpecific(IAdvanced item)
{
    return false;
}

请注意,IAdvanced接口从IBase接口派生/继承。

我发现如果我调用DoSomething,其中项目的类型为IAdvanced,它仍然总是返回false。 我不明白这一点。 我知道,因为IAdvanced是一个类型IBase(因为它是这个接口的子代),它可能会导致DoSomethingSpecific方法的2个重载类型之间的混淆。 但是,正如我对有限的C#知识所理解的那样,应该在这里选择IAdvanced方法。 这是我如何得出这个结论的一个例子:

public class Advanced: IAdvanced
{

   public void CallMethod()
   {
      DoSomething(this);
   }
}

这导致了真正的价值。

但是,如果我这样做:

public class Advanced: IAdvanced
{

    public void CallMethod()
    {
       DoSomethingSpecific(this);
    }
}

它返回false,这是我所期望的。

我不得不说我之前从未使用过仿制药。 我曾试过,但总是陷入这样的情况,然后完全没有看到使用泛型的意义(除了树和链表之类的数据结构)。

这次我决定来这里寻求一些建议。 我试图做的是否有明显的问题? 尝试做我在这里忙的事情可能没有意义吗?

我无法重现这一点,这意味着其他可能正在发生。 我怀疑你实际上想说它总是回归真实 这就是我在这里看到的:

using System;

public interface IBase {}
public interface IAdvanced : IBase {}

public class Base : IBase {}
public class Advanced : IAdvanced {}

class Test
{
    public static bool DoSomething<T>(T item) where T: IBase
    {
        return DoSomethingSpecific(item);
    }

    public static bool DoSomethingSpecific(IBase item)
    {
        return true;
    }

    public static bool DoSomethingSpecific(IAdvanced item)
    {
        return false;
    }

    static void Main()
    {
        Console.WriteLine(DoSomething(new Base()));     // True
        Console.WriteLine(DoSomething(new Advanced())); // True
    }    
}

现在你也写:

我知道,因为IAdvanced是一个类型IBase(因为它是这个接口的子代),它可能会导致DoSomethingSpecific方法的2个重载类型之间的混淆。 但是,正如我对有限的C#知识所理解的那样,应该在这里选择IAdvanced方法。

当然,你应该期望返回false - 而我希望返回true

你看, DoSomething<T>的重载决议是在编译该方法时确定的。 这种选择只做一次 - 对于每个不同的T都不是一次。 因此,如果您查看已编译的IL中的DoSomething<T> ,您将看到对DoSomethingSpecific(IBase)的调用,而不是 DoSomethingSpecific(IAdvanced) 这里没有多态性。

至于如何“修复”这个 - 你需要更详细地解释你真正想要实现的目标。 特别是,如果你有这个代码,你会想要发生什么:

IBase x = new AdvancedImplementation();
DoSomething(x);

这里的T将是IBase ,但该将指IAdvanced的实现。 如果你想在这种情况下执行DoSomethingSpecific(IAdvanced) ,并且你正在使用C#4,那么你可以使用动态类型:

public static bool DoSomething(IBase item)
{
    dynamic dynamicItem = item;
    // Dispatch dynamically based on execution-time type
    return DoSomethingSpecific(dynamicItem);
}

请注意该方法不再需要通用 - 它不会带来任何好处。

另一方面,如果您想要决定仅基于T调用哪个,则需要使用类似ivowiblo的解决方案。

就个人而言,我会尽量避免这两种解决方案 - 我通常会发现这种事情是设计的一种症状,可以通过其他方式得到改善。

我会删除编译时检查并使其成为运行时:

public bool DoSomething(IBase item)
{
    var itemAdvanced = item as IAdvanced;
    if (itemAdvanced != null)
        return DoSomethingSpecific(itemAdvanced);
    else
        return DoSomethingSpecific(item);
}

原因是如果你的调用者只是静态地知道对象是一个IBase ,但是在运行时它是一个IAdvanced ,不是首选将它当作IAdvanced吗? 这可能也是做你想做的最快的方式。 如果你看到需要,我只会采用dynamic方法,例如因为可能存在大量不同的方法。

据他所知,这是一个IBase。 编译器需要确定你调用哪种方法,这就是它总是选择那个方法的原因。

一个肮脏的技巧将是这样做:

public static bool DoSomething<T>(T item) where T: IBase
{
    var isAdvanced = typeof(IAdvanced).IsAssignableFrom(typeof(T));
    return isAdvanced ? DoSomethingSpecific((IAdvanced)item) : DoSomethingSpecific(item);
}

另一种方法是使用Double-Dispatch / Visitor模式:

public interface IDoSomethingVisitor {
    bool DoSomethingSpecific(IBase base);
    bool DoSomethingSpecific(IAdvanced adv);
}

DoSomething方法将在您的IBase界面中:

public interface IBase{
    void DoSomething(IDoSomethingVisitor visitor);
}

在您的实施中:

public class Base : IBase
{
   public bool DoSomething(IDoSomethingVisitor visitor)
   {
      visitor.DoSomething(this);
   }
}

public class Advanced : IAdvanced
{
   public bool DoSomething(IDoSomethingVisitor visitor)
   {
      visitor.DoSomething(this);
   }
}

在这种情况下,使用纯继承解决问题。 实际的实例是解析调用哪个方法的实例。 不,如果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM