具有仅适用于某些类型参数的方法的泛型类

时间:2009-08-29 16:55:52

标签: c# generics types interface

假设您正在编写库以在屏幕上显示内容,因此您创建了一个IDisplayable界面。此接口有一种方法可以从对象创建控件:displayable.GetControl()

您想要创建自己的列表类型,可以显示:MyList<T>。现在只有TIDisplayable时才会显示此列表,因此您可以在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#中的这个问题?

5 个答案:

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