在重载方法中使用泛型类型
本文关键字:泛型类型 重载 方法 | 更新日期: 2023-09-27 18:35:39
我有一个通用方法:
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,这就是我所期望的。
我不得不说,我以前从未使用过泛型。我已经尝试过,但总是卡在这样的情况下,然后完全看不到使用泛型的意义(除了树和链表等数据结构)。
这次我决定来这里寻求一些建议。我想做的事情有明显的问题吗?尝试做我在这里忙于做的事情也许没有意义吗?
我无法重现这一点,这意味着可能正在发生其他事情。我怀疑你的意思是说它总是返回 true。这就是我在这里看到的:
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
来决定调用哪个,则需要使用类似 ivowifblo 的解决方案。
就我个人而言,我会尽量避免这两种解决方案 - 我通常会发现这种事情是可以通过其他方式改进的设计的症状。
我会删除编译时检查并使其运行时:
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);
}
另一种方法是使用双重派送/访客模式:
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);
}
}
在这种情况下,使用纯继承解决问题。实际实例是解析要调用的方法的实例。没有如果。