泛型与泛型参数和抽象类

24
我有两个通用基类。第二个通用类在其第一个类的参数上具有约束条件。
abstract class FirstClass<T> {...}

abstract class SecondClass<U> where U : FirstClass {...}

这是无法正常工作的,因为 FirstClass 没有被定义。因此我需要这样做。

abstract class FirstClass<T> {...}

abstract class SecondClass<U, T> where U : FirstClass<T> {...}

这种方法可以实现功能。但是,这样会使得实现这些抽象类变得丑陋。

class SomeClass {...}

class MyFirstClass : FirstClass<SomeClass> {...}

class MySecondClass : SecondClass<MyFirstClass, SomeClass> {...}

我觉得这种写法有些冗余,因为我重复了两次SomeClass。有没有一种方法可以声明它,使得FirstClass中的T自动成为SecondClass中的U。我真正想要的代码是这样的。

class SomeClass {...}

class MyFirstClass : FirstClass<SomeClass> {...}

class MySecondClass : SecondClass<MyFirstClass> {...}

我怀疑这种情况不太可能发生,有没有更简洁的方法来达到我想要做的事情?
编辑
有几个人建议创建一个 IFirstClass 接口。但我的定义更接近这样。
class FirstClass<T>
{
    public T MyObj { get; set; }
}

class SecondClass<U, T> where U : FirstClass<T>
{
    U MyFirstClass { get; set; }
}

我无法从SecondClass访问MyFirstClass.MyObj的接口。虽然我可以在IFirstClass上创建一个object T MyObj { get; set; },然后使用new来隐藏它,但如果我这样做,Silverlight在绑定时会出现问题。


虽然我在问题中没有提到Silverlight,但这是一个Silverlight项目。我不确定这是否会限制解决方案。 - cadrell0
如果您尝试将 WCF RIA Services 的 TypeOf<T> 作为 POCO 类型进行编排,那么它会限制解决方案,因为泛型无法在不进行一些主要的变通的情况下公开为 WCF 或 WCF RIA Services。 - Keith Adler
你是否使用了任何关于FirstClass<U>的类型特定信息?如果没有,我倾向于在这些情况下使FirstClass<U>匹配某个IGenericFirstClass接口,然后将约束指定为IGenericFirstClass。它可以隐藏类型U的依赖性。 - J Trana
UT是不同的类型吗? - Stefan Steinegger
@Stefan - 我编辑了代码,试图澄清。 - cadrell0
由于泛型的编译时本质,存在某个点它就不会再继续进行下去了。这时你就得退回到老式、丑陋的向下转型了... - Stefan Steinegger
4个回答

12

按我的经验,创建非通用接口以操作泛型类最为简单。同时,这种方法也解决了在不知道泛型类型的情况下需要转换到基类的问题。

interface IFirstClass {...}

abstract class FirstClass<T> : IFirstClass {...}

abstract class SecondClass<T> where T : IFirstClass {...}

请查看我的编辑。我还没有遇到需要转换为基类的问题。 - cadrell0

11

如果您实际上正在使用泛型类型参数来调用FirstClass(从您的编辑中可以看出),那么很遗憾,您要寻找的是不可能的。编译器不能区分相关和不相关的类型参数。


1
这正是我所想的,但如果我们没有希望,那我们还有什么? - cadrell0
@cadrell0: careers.stackoverflow.com ;) 不过说真的,别忘了接受这些答案中的一个。这几乎是您唯一的选择。 - Adam Robinson

2
创建一个FirstClass实现的接口。然后可以将SecondClass限制为该接口。

0

这实际上是对具有两个通用参数的接口,自动解决一个的答案,该问题已被标记为此问题的重复。

您可以声明一堆具有特定Id类型的接口。虽然不是完美的解决方案,但简化了实体类的声明。

public interface IIntPersistentEntityService<TPersistentEntity>
        : IPersistentEntityService<TPersistentEntity, int>
    where TPersistentEntity : IPersistentEntity<int>
{
}

public interface IStringPersistentEntityService<TPersistentEntity>
        : IPersistentEntityService<TPersistentEntity, string>
    where TPersistentEntity : IPersistentEntity<string>
{
}

那么User类可以这样声明:

public class UserService : IIntPersistentEntityService<User>
{
    public User Get(int id)
    {
        throw new NotImplementedException();
    }
}

如果您没有匹配的ID类型,将会出现编译器错误。


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