简体   繁体   English

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

[英]Use of generic types in overloaded methods

I have a generic method: 我有一个通用的方法:

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;
}

Note that IAdvanced interface derives/inherits from IBase interface. 请注意,IAdvanced接口从IBase接口派生/继承。

I have found that if I call DoSomething where the item is of type IAdvanced, it still always returns false. 我发现如果我调用DoSomething,其中项目的类型为IAdvanced,它仍然总是返回false。 I don't understand this. 我不明白这一点。 I know that since IAdvanced is a type IBase (as it is a child of this interface), it may cause confusion between the 2 overloaded types of the DoSomethingSpecific method. 我知道,因为IAdvanced是一个类型IBase(因为它是这个接口的子代),它可能会导致DoSomethingSpecific方法的2个重载类型之间的混淆。 However, as I understand with my limited C# knowledge, the IAdvanced method should be chosen here. 但是,正如我对有限的C#知识所理解的那样,应该在这里选择IAdvanced方法。 This is an example of how I made this conclusion: 这是我如何得出这个结论的一个例子:

public class Advanced: IAdvanced
{

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

This results in a true value. 这导致了真正的价值。

However, if I do: 但是,如果我这样做:

public class Advanced: IAdvanced
{

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

It returns false, which is what I would expect. 它返回false,这是我所期望的。

I have to say that I have never used generics before. 我不得不说我之前从未使用过仿制药。 I have attempted though, but always get stuck on a case like this, and then completely fail to see the point of using generics (besides data structures such as trees and linked lists). 我曾试过,但总是陷入这样的情况,然后完全没有看到使用泛型的意义(除了树和链表之类的数据结构)。

This time I decided to come here for some advice. 这次我决定来这里寻求一些建议。 Is there a clear problem with what I am trying to do? 我试图做的是否有明显的问题? Does it perhaps not make sense to try and do what I am busy doing here? 尝试做我在这里忙的事情可能没有意义吗?

I can't reproduce this, which means that something else is probably going on. 我无法重现这一点,这意味着其他可能正在发生。 I suspect you actually meant to say that it always returns true . 我怀疑你实际上想说它总是回归真实 That's what I see here: 这就是我在这里看到的:

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
    }    
}

Now you also write: 现在你也写:

I know that since IAdvanced is a type IBase (as it is a child of this interface), it may cause confusion between the 2 overloaded types of the DoSomethingSpecific method. 我知道,因为IAdvanced是一个类型IBase(因为它是这个接口的子代),它可能会导致DoSomethingSpecific方法的2个重载类型之间的混淆。 However, as I understand with my limited C# knowledge, the IAdvanced method should be chosen here. 但是,正如我对有限的C#知识所理解的那样,应该在这里选择IAdvanced方法。

Surely then you should expect false to be returned - whereas I expect true to be returned. 当然,你应该期望返回false - 而我希望返回true

You see, the overload resolution within DoSomething<T> is determined when that method is compiled. 你看, DoSomething<T>的重载决议是在编译该方法时确定的。 That choice is made once - not once for every different T . 这种选择只做一次 - 对于每个不同的T都不是一次。 So if you look in the compiled IL for DoSomething<T> , you'll only see a call to DoSomethingSpecific(IBase) , never DoSomethingSpecific(IAdvanced) . 因此,如果您查看已编译的IL中的DoSomething<T> ,您将看到对DoSomethingSpecific(IBase)的调用,而不是 DoSomethingSpecific(IAdvanced) There's no polymorphism here. 这里没有多态性。

As for how you can "fix" this - you'd need to explain in more detail what you really want to achieve. 至于如何“修复”这个 - 你需要更详细地解释你真正想要实现的目标。 In particular, what would you want to happen if you had this code: 特别是,如果你有这个代码,你会想要发生什么:

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

Here T would be IBase , but the value would refer to an implementation of IAdvanced . 这里的T将是IBase ,但该将指IAdvanced的实现。 If you want DoSomethingSpecific(IAdvanced) to be executed in this case, and if you're using C# 4, then you can use dynamic typing: 如果你想在这种情况下执行DoSomethingSpecific(IAdvanced) ,并且你正在使用C#4,那么你可以使用动态类型:

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

Note how the method doesn't need to be generic any more - it would give no benefit. 请注意该方法不再需要通用 - 它不会带来任何好处。

If, on the other hand, you want to decide which to call solely based on T , you'd need to use something like ivowiblo's solution. 另一方面,如果您想要决定仅基于T调用哪个,则需要使用类似ivowiblo的解决方案。

Personally I would try to avoid both of these solutions - I usually find that this sort of thing is a symptom of a design which can be improved in other ways. 就个人而言,我会尽量避免这两种解决方案 - 我通常会发现这种事情是设计的一种症状,可以通过其他方式得到改善。

I would drop the compile-time check and make it runtime: 我会删除编译时检查并使其成为运行时:

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

The reason is that if your caller only statically knows of the object as an IBase , but at runtime it's an IAdvanced , wouldn't it be preferred to treat it as an IAdvanced ? 原因是如果你的调用者只是静态地知道对象是一个IBase ,但是在运行时它是一个IAdvanced ,不是首选将它当作IAdvanced吗? This is probably also the fastest way to do what you want. 这可能也是做你想做的最快的方式。 I'd only go for the dynamic approach if you see a need to, eg because there could be a great number of different methods. 如果你看到需要,我只会采用dynamic方法,例如因为可能存在大量不同的方法。

As far as it knows, it's an IBase. 据他所知,这是一个IBase。 The compiler needs to deside which method are you calling and that's why it's choosing that one always. 编译器需要确定你调用哪种方法,这就是它总是选择那个方法的原因。

A dirty trick will be to do this: 一个肮脏的技巧将是这样做:

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

Another way is to use Double-Dispatch/Visitor pattern: 另一种方法是使用Double-Dispatch / Visitor模式:

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

The DoSomething Method will be in your IBase interface: DoSomething方法将在您的IBase界面中:

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

And in your implementations: 在您的实施中:

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

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

In this case, the problem is solved using pure inheritance. 在这种情况下,使用纯继承解决问题。 The actual instance is the one that resolves which method to call. 实际的实例是解析调用哪个方法的实例。 No ifs. 不,如果。

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

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