假设您正在编写库以在屏幕上显示内容,因此您创建了一个IDisplayable
界面。此接口有一种方法可以从对象创建控件:displayable.GetControl()
。
您想要创建自己的列表类型,可以显示:MyList<T>
。现在只有T
是IDisplayable
时才会显示此列表,因此您可以在MyList类中询问T应该实现IDisplayable。但是当T不是IDisplayable时,你也想在某些地方使用这个列表类型(结果这个列表不可显示)。那么可以说如果T实现了IDisplayable,MyList会实现IDisplayable吗?如果MyList<T>
总是实现IDisplayable但是如果你尝试调用GetControl()
如果T不是IDisplayable,我也会很高兴,但是我想知道是否存在静态类型安全这样做的方式。可以这样做吗?或者我正在寻找错误的解决方案?
编辑:
我同意到目前为止MyList可能有太多责任的建议。我最初的想法是创建一个MyDisplayableList<T> : MyList<T> (where T : IDisplayable)
。
这种方法的问题在于我有很多方法采用MyList并返回MyList(例如Linq中的Select等方法)。因此,如果我在MyDisplayableList上使用select,我会返回一个MyList,即使它是MyList,我也无法显示它...是否有一种类型安全的方法来处理C#中的这个问题?
答案 0 :(得分:8)
你描述它是不可能的。您应该创建两种类型的列表:
public class MyList<T> : IList<T>
{
...
}
public class MyDisplayableList<T> : MyList<T> where T : IDisplayable
{
...
}
答案 1 :(得分:5)
简单。检查类型是否为IDisplayable
。如果不是,请抛出InvalidOperationException
:
if (!typeof(IDisplayable).IsAssignableFrom(typeof(T)))
throw new InvalidOperationException();
或者,如果您有T
的实例,只需查看:
IDisplayable disp = instanceOfT as IDisplayable;
if (disp == null)
throw new InvalidOperationException();
// do stuff with `disp`.
但您的设计可能存在缺陷。你可能会在课堂上投入太多而违反单一责任原则。首先重新检查你的设计。
答案 2 :(得分:1)
你甚至在这里需要仿制药吗?
我猜你有多个实现IDisplayable
的类,并希望将它们的所有实例放在同一个列表中。所以你只需要一个
public class MyList : Collection<IDisplayable>, IDisplayable
{
public void GetControl()
{
foreach (IDisplayable displayable in this)
{
displayable.GetControl();
}
}
}
如果你真的想在该列表中放入非IDisplayable
个实例,找到公共基类并定义一个
public class MyList2 : Collection<object>, IDisplayable
{
public void GetControl()
{
foreach (IDisplayable displayable in this.OfType<IDisplayable>())
{
displayable.GetControl();
}
}
}
答案 3 :(得分:1)
我认为您希望MyList<T>
能够同时使用IDisplayable
和非IDisplayable
的原因是因为有一些重复的功能。
我建议您将基本实现作为MyListBase<T>
来实现列表执行的基本功能。然后你有MyDisplayableList继承MyList(MyDisplayableList<T> : MyList<T> where T : IDisplayable
),它执行特定于IDisplayable的函数。
如果有任何特定于非IDisplayble的功能,请添加NonDisplayableList<T> : MyListBase<T>
以执行这些功能。
答案 4 :(得分:1)
我认为这个问题的一个更好的解决方案是从列表中抽象出来并想出IDisplayable
public class CompositeDisplayable : IDisplayable {
public void Add(IDisplayable displayable) {
// TODO: check for null, cycles, etc...
_list.Add(displayable);
}
public void Remove(IDisplayable displayable) {
// TODO: check for null
_list.Remove(displayable);
}
public Control GetControl() {
var control = new Control();
// this assumes Control is also a composite type
_list.ForEach(displayable => control.Add(displayable.GetControl()));
return control;
}
private List<IDisplayable> _list = new List<IDisplayable>();
}
的{{3}}。这正是控件在ASP.NET或Windows窗体中建模的方式,例如。
public static class DisplayableExtensions {
public static IDisplayable ToDisplayable(this IEnumerable source) {
if (source == null) throw new NullReferenceException(); // extension method should behave like instance methods
var result = new CompositeDisplayable();
source.
OfType<IDisplayable>().
ToList().
ForEach(displayable => result.Add(displayable));
return result;
}
}
然后,要将您的“某物”集合与复合物联系起来,您可以创建一个这样的扩展方法:
{{1}}