从泛型类继承时需要T的列表或者枚举器的建议

时间:2020-03-05 18:50:30  来源:igfitidea点击:

我知道答案将不会很简单,而且我已经使用了一些(我认为很丑陋)的方法。我只是在寻找一些优雅的答案。

抽象类:

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的集合(或者其他类似的组,泛型或者其他),然后利用MyObjects基类的ToList方法,因为此时我们还不特别了解T的类型。

编辑
对于特定的示例,每当出现这种情况时,我都会考虑一会儿,然后做一些不同的事情,因此没有当前的要求。但是由于它经常出现,所以我想我会把它浮动。

编辑
@Sara,它不是我关心的集合的特定类型,它可以是一个List,但是每个实例的ToList方法仍然相对不可用,没有匿名类型)

@aku,是的,这个问题可能是相对假设的,但是能够知道对象的基本类型将非常有用,但是能够检索并处理T个对象列表。让ToList返回BaseType列表是我的解决方法之一

编辑@全部:到目前为止,这一直是我希望进行的讨论,尽管它在很大程度上证实了我的怀疑。到目前为止,非常感谢,但是还有其他人可以随意输入。

EDIT @ Rob,是的,它适用于已定义的类型,但仅当该类型被称为IOtherObjects列表时无效。

@Rob再次感谢。这通常是我的笨拙变通方法(不要轻视:))。或者使用ConvertAll函数通过委托向下转换。感谢我们抽出宝贵的时间来理解问题。

如果我有点困惑,可以对编辑进行资格审查

更准确地说,(我可能对此的最新实现过于复杂了):

可以说我有两种对象类型,B和C从对象A继承。

许多场景都显示了自己的位置,从B列表或者C列表,或者在其他情况下从B列表或者C列表,但我不知道如果我在基类中,我需要一个不太具体的A列表。

上面的示例是"不太具体问题列表"最新化身的简化示例。

通常,它会自我展示,因为我认为在可能的情况下会限制需要编写的代码量,并且看上去比其他选项要优雅一些。我真的很想讨论关于可能性和其他观点的讨论,我或者多或者少都对此有所了解。令我惊讶的是,到目前为止,还没有人提到ConvertAll(),因为这是我使用的另一种解决方法,但是对于手头的场景来说太冗长了

@罗伯再一次和萨拉

谢谢,但是我确实感到我在所有静态上下文荣耀中都了解泛型,并且确实了解此处的问题。

我们系统的实际设计及其使用的泛型(我可以说这没有一点偏见,因为我只是设计中的一员)。就是在我使用核心API的时候,我发现有些情况下我在做简单事情的时候就处于错误的境地,相反,我不得不以比我所喜欢的稍微优雅一些​​的方式来处理它们(尝试使自己变得更聪明)也许是懒惰,我会接受其中任何一个标签)。

我不喜欢所谓的"笨拙",主要是因为我们需要遍历记录集,只是将对象转换为其基本值,这可能会降低性能。

我想我想知道以前是否有人在他们的编码中遇到过这种情况,以及是否有人在处理它时比我聪明,或者至少比我更优雅。

解决方案

回答

在情况下,MyObjectsA和MyObjectsB没有共同的前身。通用类是不同类的模板,而不是通用基类。如果要在不同的类中具有公共属性,请使用接口。我们不能在循环中调用ToList,因为它在不同的类中具有不同的签名。我们可以创建返回对象而不是特定类型的ToList。

回答

为什么会有MyObjects的集合?我们没有清单是有特定原因的吗?

回答

我们仍然可能可以访问ToList()方法,但是由于我们不确定类型,因此行不通吗?

foreach(var myObject in myObjectsList)
    foreach(var obj in myObject.ToList())
        //do something

当然,这仅适用于C3.0。

请注意,使用var只是为了消除了解列表包含的类型的要求。与弗兰克(Frank)的评论相反,我有一种幻想,即var将使输入动态化。

回答

泛型用于静态时间类型检查,而不是运行时调度。使用继承/接口进行运行时调度,使用泛型进行编译时类型保证。

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

(显然,我更喜欢Enumerables而不是List。)

或者仅使用适当的动态语言,例如VB。 :-)

回答

好的,我很困惑,以下代码对我来说很好(好奇心使我更好!):

// Original Code Snipped for Brevity - See Edit History if Req'd

还是我错过了什么?

根据OP更新响应

好吧,现在我真的很困惑。
我们要说的是要从通用/抽象列表中获取类型值列表吗? (因此,子类无关紧要)。

如果类型是它们不匹配的子代/接口实现者,则不能返回类型列表!我们当然可以从抽象List中获取特定类型的项目的List,如下所示:

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()获取接口类型的List。这应该在我们遇到的任何情况下都有效。有帮助吗?

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.

并能够选择其中的类型,我们还能怎么做?我感觉到我们不太了解泛型的意义,而我们正试图让它们做一些他们不适合做的事情!

回答

如果你有

class B : A
class C : A

你有

List<B> listB;
List<C> listC;

我们希望将其视为父类型的列表

那你应该用

List<A> listA = listB.Cast<A>().Concat(listC.Cast<A>()).ToList()

回答

我最近发现了

List<A>.Cast<B>().ToList<B>()

图案。

正是我想要的,