![](/img/trans.png)
[英]Should overloaded methods with value types be consolidated into a generic method?
[英]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.