我有一个对象层次结构,用于在asp.net mvc中生成UI控件,并尝试实现流畅的API。 我创建了一些虚拟类来关注当前的问题。
这是“错误”的代码库:
public abstract class HtmlElement { /* ... */ }
public abstract class UIElement : HtmlElement { /* ... */ }
public abstract class ButtonBase : UIElement { /* ... */ }
public class LinkButton : ButtonBase { /* ... */ }
public class ActionButton : ButtonBase { /* ... */ }
public static class HtmlElementExtensions
{
public static T Id<T>(this T item, string id) where T : HtmlElement
{
/* set the id */
return item;
}
}
public static class ButtonBaseExtensions
{
public static T Id<T>(this T item, string id) where T : ButtonBase
{
/* set the id and do some button specific stuff*/
return item;
}
}
当我尝试调用LinkButton上的Id时,编译器会提示存在模糊的调用:
LinkButton lb = new LinkButton().Id("asd");
我本以为编译器会在这种情况下选择最接近的匹配项,因此如果我有一个从HtmlElement继承的Script类,那么将调用HtmlExtensions Id方法,对于LinkButton(由于限制),将调用ButtonBase方法。
我有一个解决方案,但我不确定是否有更好的解决方案。
我从ButtonBaseExtensions中删除了Id方法,并将HtmlElementExtensions Id方法修改为以下方式:
public static T Id<T>(this T item, string id) where T : HtmlElement
{
if (item is ButtonBase)
{
/* do some button specific stuff*/
}
/* set the id */
return item;
}
这样每个继承自ButtonBase的类都可以正常工作。 我不是很喜欢我的解决方案,因为它将HtmlElement逻辑与ButtonBase逻辑混合了。 有更好的解决方案或建议吗? 我曾经考虑过将它们放在不同的命名空间中,但只是一时的想法。因为我需要同时使用两个命名空间,所以并没有解决问题。
您认为值得在MSDN论坛上提出一个想法,让编译器监视泛型扩展方法的限制吗?
与此同时,我进行了更多的研究,并在MSDN论坛上发起了一个帖子:链接
我尝试了一些非泛型的扩展方法:
public class BaseClass { /*...*/ }
public class InheritedClass : BaseClass { /*...*/ }
public static class BaseClassExtensions
{
public static void SomeMethod(this BaseClass item, string someParameter)
{
Console.WriteLine(string.Format("BaseClassExtensions.SomeMethod called wtih parameter: {0}", someParameter));
}
}
public static class InheritedClassExtensions
{
public static void SomeMethod(this InheritedClass item, string someParameter)
{
Console.WriteLine(string.Format("InheritedClassExtensions.SomeMethod called wtih parameter: {0}", someParameter));
}
}
如果我实例化这些对象:
BaseClass bc = new BaseClass();
InheritedClass ic = new InheritedClass();
BaseClass ic_as_bc = new InheritedClass();
bc.SomeMethod("bc");
ic.SomeMethod("ic");
ic_as_bc.SomeMethod("ic_as_bc");
生成了以下输出:
BaseClassExtensions.SomeMethod called wtih parameter: bc
InheritedClassExtensions.SomeMethod called wtih parameter: ic
BaseClassExtensions.SomeMethod called wtih parameter: ic_as_bc
谢谢,
彼得