创建一个泛型列表

5

我有一个实体类的基类

public class Entity<T> where T : Entity<T>, new()
{
    public XElement ToXElement()
    {
    }
    public static T FromXElement(XElement x)
    {
    }
}

我必须使用这种奇怪的结构 Entity<T> where T : Entity<T>,因为我想让静态方法FromXElement具有强类型。 另外,我有一些实体,就像这样

public class Category : Entity<Category>
{
}
public class Collection : Entity<Collection>
{
}

如何使用基类创建我的实体的通用列表?
var list = new List<Entity<?>>();
list.Add(new Category());
list.Add(new Collection());

你想要实现什么目标?为什么需要在集合中使用这些不同类型的元素? - D Stanley
而类别和集合这两个类是泛型类型,它们本身就是泛型。 - Daniel Persson
1
@DanielPersson 这被称为“奇妙的重复模板模式”(curiously repeating template pattern)。(http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx) - D Stanley
好的,我明白了。谢谢你澄清这个问题 :) - Daniel Persson
如果_Entity<Category>_的唯一目的是访问_FromXElement_,则不需要该约束。只需从_Entity<T>_(即_Category : Entity<Category> { }_)派生即可,并通过_Category.FromXElement(element)_调用它,这将具有强类型返回值_Category_。 - NKeddie
我需要在基类中有FromXElement/ToXElement,并且FromXElement应该是强类型的。这可行吗? - Evgraf
5个回答

4
你不能使用这个定义。除了object之外,CategoryCollection之间没有“公共基类”。如果有的话,比如Entity<T>被定义为:
public class Entity
{
}

public class Entity<T> : Entity where T : Entity<T>, new()
{
    public XElement ToXElement()
    {
    }
    public static T FromXElement(XElement x)
    {
    }
}

那么你可以这样做:
var list = new List<Entity>();
list.Add(new Category());
list.Add(new Collection());

但是,那会给你带来什么好处呢?


我需要在基类中使用FromXElement/ToXElement。这不适合。 - Evgraf
@Evgraf - 那么你必须进行强制类型转换。由于它们具有不同的返回类型,因此既CategoryCollection都没有实现 FromXElement 方法。 - D Stanley

1
创建一个标记接口:
public interface IAmAGenericEntity { }

public class Entity<T> where T : IAmAGenericEntity, new()
// ...

public class Category : Entity<T>, IAmAGenericEntity
// ....

var list = new List<IAmAGenericEntity>();
// ...

1
Entity缺少abstract标记,我推断To/FromXElement使用反射,并且应该适用于Entity的任何子类型。我建议您按以下方式构造类:
public class Entity
{
    public XElement ToXElement() { ... }

    protected static T FromXElement<T>(XElement x)
        where T : Entity
    {
        ...
    }
}

public class Category : Entity
{
    public static Category : FromXElement(XElement x)
    {
        return FromXElement<Category>(x);
    }
}

"样板文件"很少,不需要创造性地规避类型系统。您不必担心缺乏公共基础或手动转换的问题。如果您愿意,您可以完全消除样板文件,并直接从 Entity 构建您的对象:

public class Entity
{
    public XElement ToXElement() { ... }

    public static T FromXElement<T>(XElement x)
        where T : Entity
    {
        ...
    }
}

实质上,您正在实现一种类型类,而 C# 并不直接支持。有许多方法可以解决这个问题,但我通常发现它们更麻烦,特别是当涉及到静态方法时。如果 C# 支持静态扩展方法,那就简单了,但遗憾的是它并不支持。

0
您可以定义一个非泛型类作为所有实体类的基类。
public class Entity
{
}

让实体继承实体

public class Entity<T> : Entity where T : Entity<T>, new()
{
}

现在你可以创建实体列表,如下所示:
var list = new List<Entity>();

0
你可以通过添加一个非泛型版本的类来解决这个问题。
class Entity
{
  // methods

  public T As<T>() 
  { 
    if (this is T) return (T)this;
    throw new InvalidCastException();
  }
}

class Entity<T> : Entity where T : Entity<T>, new()

class Cathegory : Entity<T> {}

然后创建基类列表:

var list = new List<Entity>()
list.Add(new Cathegory());

然后,如果您想调用“通用特定”操作,则需要调用“As”函数或仅对对象进行强制转换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接