从列表中获取可能包含其他类型的泛型类型的所有项目的列表 [英] Get list of all items of a generic type from list which could contain other types

查看:90
本文介绍了从列表中获取可能包含其他类型的泛型类型的所有项目的列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,这很棘手。假设我有一个清单:

 清单< Foo>我的列表; 

Foo 是一个常见的抽象类,它是用于系统中的所有组件。其中一些组件类是通用的:

  public class Bar< T> :Foo 
{
public void MethodCommonToAllBar()
{
...
}
}

有些类可能会扩展通用类:

  public class Baz:Bar< int> 
public class Bat:Bar< string>

我想从 MyList 一组所有类型为 Bar< anything> 的对象,以便我可以在每个对象上调用 MethodCommonToAllBar()那些东西。如果不是泛型,我可以使用如下行:

  foreach(Baz baz in MyList.Where( x => x是Baz))
{
baz.MethodCommonToAllBar();
}
foreach(Bat bat in MyList.Where(x => x is Bat))
{
bat.MethodCommonToAllBar();
}

甚至是

<$在MyList.Where中的Bar< int> bar(x => x是Bar< int>))
{
bar.MethodCommonToAllBar();
}
foreach(MyList.Where中的Bar< string> bar(x => x是Bar< string>))
{
bar.MethodCommonToAllBar();
}

但似乎没有办法让任何对象类型 Bar ,除非我分开处理每个潜在的子类型。有没有解决方法?假设我不能以任何方式改变类结构。 (我可以,但是这是一个很大的项目,这样的改变会影响很多人,所以不太可能得到批准。理想情况下,我会在 Foo之间添加另一个非泛型类 Bar< T> 来存储该方法和其他任何常见的东西,然后搜索它。这个游戏现在正在进行重构)。我还可以看到一个涉及Reflection的解决方法,但这看起来像是矫枉过正,并且可能会导致性能下降。有没有其他方法可以干净地处理这个问题?解决方案

$ c> Bar< X> 和 Bar< Y> 不兼容!它们只是源自共同祖先的两种不同类型。它们都是同一个开放泛型类型的具体实现的事实没有区别。
您想如何处理它们?假设您从列表中检索到 Bar <?>> 类型的未知泛型类型的对象,并且您有一个方法

  void ProcessBar< T>(){...} 

你从哪里知道 T 的正确值?请注意, T 在编译时解析,而不是在运行时!这就是泛型的用途:通过保持类型安全来提供一定的灵活性。只有在编译时才能实现类型安全。

解决此问题的一种方法实际上是在继承层次结构中引入非泛型中间类型。如果你不能改变继承层次,让所有 Bar< T> 实现一个非泛型接口 IBar

  public interface IBar 
{
void MethodCommonToAllBar();
}

并简单地使用

  foreach(IBar bar in MyList.OfType< IBar>())
{
bar.MethodCommonToAllBar(); // IBar中定义的方法。

请注意 OfType<>

另一种方法是不使用泛型,并使用对象键入 Bar 类以获得最大的动态灵活性。



类型安全性和动态灵活性是对手。


Okay, this is tricky. Say I have a list:

List<Foo> MyList;

Foo is a common abstract class which is used for all components in the system. Some of these component classes are generic:

public class Bar<T> : Foo
{
    public void MethodCommonToAllBar()
    {
        ...
    }
}

And some classes may extend the generic ones:

public class Baz : Bar<int>
public class Bat : Bar<string>

I'd like a way to extract from MyList a set of all objects of type Bar<anything>, so that I may call MethodCommonToAllBar() on each of those things. If it weren't for the generic here, I could use a line like:

foreach (Baz baz in MyList.Where(x => x is Baz))
{
    baz.MethodCommonToAllBar();
}
foreach (Bat bat in MyList.Where(x => x is Bat))
{
    bat.MethodCommonToAllBar();
}

or even

foreach (Bar<int> bar in MyList.Where(x => x is Bar<int>))
{
    bar.MethodCommonToAllBar();
}
foreach (Bar<string> bar in MyList.Where(x => x is Bar<string>))
{
    bar.MethodCommonToAllBar();
}

But there doesn't seem to be any way to get all objects of any type of Bar unless I treat each potential subtype separately. Is there a workaround for this? Assume that I can't change the class structure in any way. (I could, but it's a big project, and such a change would impact a lot of people, so it's unlikely I'd get it approved. Ideally, I'd add another non-generic class between Foo and Bar<T> in the hierarchy to store that method and any other such common things and just search for that. But it's a bit late in the game to go refactoring that now.) I can also see a workaround involving Reflection, but that seems like overkill, and would likely incur a performance hit to boot. Is there any other way to handle this cleanly?

解决方案

You must you be aware of the fact that the two types Bar<X> and Bar<Y> are not compatible! They are just two different types deriving from a common ancestor. The fact that they are both concrete implementations of the same open generic type makes no difference. And how do you want to process them? Assume that you retrieved an object of type Bar<?> of an unknown generic type from the list and that you have a method

void ProcessBar<T>() { ... }

Where do you know the right value of T from? Note that T is resolved at compile time, not at runtime! This is what generics are for: to provide certain flexibility by keeping type safety. And type safety can only be achieved at compile time.

One way of solving this problem is in fact to introduce a non-generic intermediate type in your inheritance hierarchy. If you cannot change the inheritance hierachy, let all Bar<T> implement a non-generic interface IBar

public interface IBar
{
    void MethodCommonToAllBar();
}

and simply filter your list with

foreach (IBar bar in MyList.OfType<IBar>())
{
    bar.MethodCommonToAllBar(); // Method defined in IBar.
}

Note that OfType<> does both, filter and cast to the required type.

Another way is to not use generics at all and to work with the object type in the Bar class for maximum dynamic flexibility.

Type safety and dynamic flexibility are opponents.

这篇关于从列表中获取可能包含其他类型的泛型类型的所有项目的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆