2009-08-29 74 views
0

假设您正在编写一个库以在屏幕上显示内容,则创建一个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#中处理此问题的安全方法?

+1

为什么你也想用MYLIST 非显示班?在我看来,你要求MyList 做太多事情,但没有理由很难说。 – 2009-08-29 17:58:06

回答

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`. 

您的设计可能是有缺陷的,虽然。你可能在课堂上太多,违反单一责任原则。首先重新检查你的设计。

+0

谢谢,这就是我要使用的。但是,如果可用,我宁愿采用静态类型安全的方法... – Jules 2009-08-29 20:17:23

+0

无法强制执行此操作(对于某些类的某些特定方法)。类型约束在类型级别执行。 – 2009-08-29 20:21:44

8

这是不可能的,因为你描述它。您应该创建两种类型的列表:

public class MyList<T> : IList<T> 
{ 
    ... 
} 

public class MyDisplayableList<T> : MyList<T> where T : IDisplayable 
{ 
    ... 
} 
+0

啊,是的,谢谢你,这是我的第一个想法,但我没有告诉你足够的。这种方法的问题是我有很多方法需要MyList 并返回MyList (例如,在Linq中选择的方法)。所以,如果我在MyDisplayableList上使用select,我返回一个MyList,并且我无法显示它......是否有一种安全的方式来处理C#中的这个问题? – Jules 2009-08-29 20:20:09

+0

然后使该方法通用:'公共TList Foo (TList列表)其中TList:MyList ' – dtb 2009-08-29 20:39:18

+0

谢谢。然而,我不明白这将如何解决问题。例如,如果我做了'aMyList.Select((a)=> a.ToDisplayable())',那么我会有一个'MyList ',但我不能在它上面调用GetControl(),因为它不是MyDisplayableList。 – Jules 2009-08-29 20:54:37

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(); 
     } 
    } 
} 
1

我认为原因你想MyList<T>能够与IDisplayable和非IDisplayable一起工作是因为有一些重复的功能。

我建议你的基本实现为MyListBase<T>,它实现了列表执行的基本功能。然后,您的MyDisplayableList继承MyList(MyDisplayableList<T> : MyList<T> where T : IDisplayable),该函数仅执行特定于IDisplayable的功能。

如果有任何特定于非IDisplayble的功能,请添加NonDisplayableList<T> : MyListBase<T>以执行这些功能。

1

我认为解决这个问题的一个更好的办法是从列表中抽象出来,然后想象一下IDisplayablecomposite。例如,这正是ASP.NET或Windows窗体中控件的建模方式。

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>(); 

} 

然后,你的“东西”的复合式集合之间的桥梁,你可以创建一个扩展方法是这样的:

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; 
    } 

} 
相关问题