题
我知道答案并不简单,而且我已经使用了一些(我认为丑陋的)木棍。我只是在寻找一些优雅的答案。
抽象类:
public interface IOtherObjects;
public abstract class MyObjects<T> where T : IOtherObjects
{
...
public List<T> ToList()
{
...
}
}
孩子们:
public class MyObjectsA : MyObjects<OtherObjectA> //(where OtherObjectA implements IOtherObjects)
{
}
public class MyObjectsB : MyObjects<OtherObjectB> //(where OtherObjectB implements IOtherObjects)
{
}
是否有可能循环遍历 MyObjects 的集合(或其他类似的分组,通用或其他),然后利用 待列表 的方法 我的对象 基类,因为我们此时并不具体知道 T 的类型。
编辑至于具体的例子,每当出现这个问题时,我都会想一想,然后做一些不同的事情,所以目前没有要求。但由于它经常出现,我想我应该把它浮动。
编辑@Sara,这不是我关心的集合的具体类型,它可能是一个 List,但每个实例的 ToList 方法仍然相对不可用,没有匿名类型)
@aku,是的,这个问题可能是相对假设的,但是能够检索并使用 T 个对象的列表,只知道它们的基本类型将非常有用。让 ToList 返回 BaseType 列表是我的解决方法之一
编辑 @ 全部:到目前为止,这一直是我所希望的讨论,尽管它在很大程度上证实了我的所有怀疑。到目前为止,谢谢大家,但其他人请随意输入。
编辑@Rob,是的,它适用于定义的类型,但当该类型仅被称为 IotherObjects 列表时则不起作用。
@抢 再次 谢谢。这通常是我笨拙的解决方法(没有不尊重的意思:))。或者使用 ConvertAll 函数通过委托向下转换。感谢您花时间了解问题。
合格编辑 以防我有点困惑
更准确地说,(我可能让我最新的实现变得过于复杂):
假设我有 2 个对象类型,B 和 C 继承自对象 A。
许多场景已经呈现在其中,从 B 列表或 C 列表,或者在其他情况下是其中任何一个列表 - 但我不知道如果我在基类中,我需要一个不太具体的列表A。
上面的例子是一个淡化的例子 不太具体的清单 问题的最新体现。
通常它已经出现了,因为我认为通过可能的场景限制了需要编写的代码量,并且看起来比其他选项更优雅一些。我真的很想讨论可能性和其他观点,我或多或少已经得到了这些。我很惊讶到目前为止没有人提到 ConvertAll(),因为这是我使用过的另一种解决方法,但对于当前的场景来说有点过于冗长
@抢 再次 和萨拉
谢谢,但是我确实觉得我理解泛型的所有静态上下文荣耀,并且确实理解这里起作用的问题。
我们系统的实际设计和泛型的使用(我可以毫无偏见地这么说,因为我只是设计中的参与者之一),已经做得很好了。当我使用核心 API 时,我发现了一些情况,当我简单地做一些事情时,我处于错误的范围内,相反,我不得不用比我喜欢的稍微不那么优雅的方式来处理它们(尝试要么聪明一点)或者也许是懒惰 - 我会接受这些标签中的任何一个)。
我对我所说的“cludge”的厌恶很大程度上是因为我们需要对记录集进行循环,只是为了将对象转换为其基本值,这可能会影响性能。
我想我想知道是否有其他人以前在编码中遇到过这个问题,以及是否有人在处理它时比我更聪明,或者至少更优雅。
解决方案
如果你有
class B : A
class C : A
你有
List<B> listB;
List<C> listC;
您希望将其视为父类型的列表
那么你应该使用
List<A> listA = listB.Cast<A>().Concat(listC.Cast<A>()).ToList()
其他提示
为什么你有一个 MyObjects 集合?您没有列表有什么具体原因吗?
在您的情况下,MyObjectsA 和 MyObjectsB 没有共同的前身。通用类是模板 不同的 类不是公共基类。如果你想在不同的类中拥有共同的属性,请使用接口。你不能打电话 待列表 在循环中,因为它在不同的类中有不同的签名。您可以创建返回的 ToList 物体 而不是具体类型。
您仍然可以访问 ToList() 方法,但由于您不确定类型,这不起作用吗?
foreach(var myObject in myObjectsList)
foreach(var obj in myObject.ToList())
//do something
当然这仅适用于 C# 3.0。
请注意,使用 var 只是为了消除了解列表包含什么类型的要求;与 Frank 的评论相反,Frank 认为 var 会让打字变得动态。
好吧,我很困惑,下面的代码对我来说效果很好(好奇心战胜了我!):
// Original Code Snipped for Brevity - See Edit History if Req'd
或者我错过了什么?
更新以下OP的响应
好吧,现在我真的很困惑..你的意思是你想获得一个列表 打字的 来自通用/抽象列表的值?(因此子类变得无关紧要)。
如果类型是子/接口实现者,则无法返回类型化列表 - 它们不匹配!您当然可以从抽象列表中获取特定类型的项目列表,如下所示:
public List<OfType> TypedList<OfType>() where OfType : IOtherObjects
{
List<OfType> rtn = new List<OfType>();
foreach (IOtherObjects o in _objects)
{
Type objType = o.GetType();
Type reqType = typeof(OfType);
if (objType == reqType)
rtn.Add((OfType)o);
}
return rtn;
}
如果我仍然偏离基地,你能改一下你的问题吗?!(看来我不是唯一一个不确定你在做什么的人)。我试图确定您是否对泛型存在误解。
另一个更新:D
是的,所以看起来您想要/需要获取类型列表或基本列表的选项,是吗?
这将使您的抽象类看起来像这样 - 您可以使用 ToList 来获取具体类型,或使用 ToBaseList() 来获取接口类型的列表。这应该适用于您遇到的任何情况。这有帮助吗?
public abstract class MyObjects<T> where T : IOtherObjects
{
List<T> _objects = new List<T>();
public List<T> ToList()
{
return _objects;
}
public List<IOtherObjects> ToBaseList()
{
List<IOtherObjects> rtn = new List<IOtherObjects>();
foreach (IOtherObjects o in _objects)
{
rtn.Add(o);
}
return rtn;
}
}
更新#3
这并不是一个真正的“笨拙”的解决方法(没有不尊重的意思)——这是唯一的方法。我认为这里更大的问题是设计/理解问题。你说你遇到了问题,这段代码解决了它。但如果你期望做类似的事情:
public abstract class MyObjects<T> where T : IOtherObjects
{
List<T> _objects = new List<T>();
public List<IOtherObjects> Objects
{ get { return _objects; } }
}
#warning This won't compile, its for demo's sake.
并且能够挑选从中产生的类型,否则如何 可以 你做吧?!我感觉你并没有真正理解泛型的意义是什么,并且你试图让它们做一些它们不是设计目的的事情!?
我最近发现了
List<A>.Cast<B>().ToList<B>()
图案。
它正是我想要的,
泛型用于静态时间类型检查 不是 运行时调度。使用继承/接口进行运行时分派,使用泛型进行编译时类型保证。
interface IMyObjects : IEnumerable<IOtherObjects> {}
abstract class MyObjects<T> : IMyObjects where T : IOtherObjects {}
IEnumerable<IMyObjects> objs = ...;
foreach (IMyObjects mo in objs) {
foreach (IOtherObjects oo in mo) {
Console.WriteLine(oo);
}
}
(显然,我更喜欢枚举而不是列表。)
或者 只需使用适当的动态语言(例如 VB)即可。:-)