我想创建一个泛型类,但该类型的where条件之一是,它必须扩展一个特定的类,不幸的是它也是泛型类。
让我解释一下,说我们已经有了这个抽象基类(并且不能改变它们,因为它是第三方框架的一部分):
public abstract class SomeGenericBaseClass<Tx> : IDisposable
where Tx : class
{
public string SomeProperty { get; set; }
}
这个基类有几个后代,用具体类型实现它,如下所示:
public class SomeConcreteClass : SomeGenericBaseClass<string>
{}
我想创建一个类,它可以包装SomeGenericBaseClass
的后代:
public class MyClass<Ta> : IDisposable
// some magig where condition, that makes sure, Ta is a descendent of SomeGenericBaseClass
{
private Ta wrappedObject;
public MyClass(Ta objectToWrap)
{
this.wrappedObject = objectToWrap;
}
public DoSomething()
{
this.wrappedObject.SomeProperty = "If I want to use this property, I have to make sure, that Ta/wrappedObject is a descendant of SomeGenericBaseClass, which declares SomeProperty.";
}
}
如何在没有where条件的情况下执行此操作
public class MyClass<Ta, Tb> : IDisposable
where Ta : SomeGenericBaseClass<Tb>, new()
where Tb : class
这意味着每次使用MyClass
var obj = new MyClass<SomeConcreteClass, string>();
虽然Ta = SomeConcreteClass
只允许一个有效的Tb类型(string
)......
答案 0 :(得分:1)
在您更新的问题中,您为我们提供了更具体的用法,Ta
= SomeConcreteClass
和Tb
= string
。
这是一个更新的代码段,用于说明如何使用我的答案:
public class SomeGenericBaseClass<Tx> : IDisposable
where Tx : class { }
public class MyClass<Ta> : IDisposable
where Ta : SomeGenericBaseClass<string>, new()
var obj = new MyClass<SomeConcreteClass>();
如果这仍然不是你想要的,那么你就没有足够清楚地解释它(除非其他人设法回答它。我们正在谈论一个非常错综复杂的设置,这意味着很多< / strong>这里的可能性,但它们的有效性取决于您的具体要求。
我的最后一个示例假设每个 MyClass<Ta>
对象都有一个Ta
SomeGenericBaseClass<string>
。
但是,如果MyClass<ASecondConcreteClass>
是SomeGenericBaseClass<int>
并且根据您的要求是正确的,那么我再次参考第3点:如果Tb
特定于Ta
{ {1}}正在被使用,那么你显然必须同时提及它们(因为Tb
属于哪个Ta
并非含糊不清。
哎呀,我在输入SO时输入了一个拼写错误。 Tx / Tb应该只有一个类约束。我编辑了这个问题。
public class SomeGenericBaseClass<Tx> : IDisposable
where Tx : class { }
public class MyClass<Ta> : IDisposable
where Ta : SomeGenericBaseClass<Tb>, new()
如果这是正确的情况,那么就没有理由提及where Tb : class
,因为已经定义了where Tx : class
因此,您可以简单地省略要求,因为它是多余的:
public class MyClass<Ta, Tb> : IDisposable
where Ta : SomeGenericBaseClass<Tb>, new()
编译器本质上需要Tb
来满足where Tx : class
的要求。
首先,你设置你的类:
public class SomeGenericBaseClass<Tx> : IDisposable
where Tx : class { }
此处SomeGenericBaseClass<Tx>
为IDisposable
,但Tx
只不过是一个类。
但是稍后你会发现一些不同的东西:
public class MyClass<Ta> : IDisposable
where Ta : SomeGenericBaseClass<Tb>, new()
where Tb : IDisposable
但是在这里,您希望Tb
(前面示例中的Tx
)本身为IDisposable
。
您的要求发生了变化。而且我不确定这是出于错误还是出于意图。我在这里看到三个选项:
Tx
/ Tb
始终需要IDisposable
这似乎是最有意义的,基于我对你想要达到的目标的假设。
public class SomeGenericBaseClass<Tx>
where Tx : class, IDisposable { }
public class MyClass<Ta> : IDisposable
where Ta : SomeGenericBaseClass<Tb>, new()
这放弃了MyClass<Ta>
需要Tb
所需的任何内容(当然只需要提及类型本身),因为您的要求已经是SomeGenericBaseClass<Tx>
定义的一部分。
注意:您也可以SomeGenericBaseClass<Tx>
IDisposable
。这没有错;但我从我的例子中省略了它,以证明它不是必要。
Tx
/ Tb
永远不需要IDisposable
如果是这种情况,那么您可能会在Tx
和SomeGenericBaseClass<Tx>
之间感到困惑,但事实上只有后者需要IDisposable
。
public class SomeGenericBaseClass<Tx> : IDisposable
where Tx : class { }
public class MyClass<Ta> : IDisposable
where Ta : SomeGenericBaseClass<Tb>, new()
Tb
有时需要IDisposable
。 IDisposable
应为MyClass<Ta>
,但SomeGenericBaseClass<Tb/Tx>
Tb
请注意,在两个之前的案例中,我在MyClass<Ta>
的类定义中省略了SomeGenericBaseClass<Tx>
的任何类型要求。这是因为在这两种情况下,类型要求都是全球性的。然后,MyClass<Ta>
的每个实例在整个应用程序中的行为方式都相同。
您想要为Tb
添加仅这一要求并非不可能。
但如果这是您想要的,那么您无法避免在MyClass<Ta>
定义中提及MyClass<Ta>
。如果类型要求仅适用于public class SomeGenericBaseClass<Tx> : IDisposable
where Tx : class { }
public class MyClass<Ta, Tb> : IDisposable
where Ta : SomeGenericBaseClass<Tb>, new()
where Tb : IDisposable
的范围,那么您必须将其置于此处(并且必须提及该类型是明显的后果)。
SomeGenericBaseClass<Tx>
请注意,在这种情况下,IDisposable
始终必须为Tx
,但IDisposable
本身必须为MyClass<A>
仅适用于{{1}} 。
但是,我认为这种设计虽然可能,但并不是一种好方法。至少,这是我的意见,因为我无法想到这个设置的有效用例。我有兴趣听听你为什么要这样使用它,如果是这样的话。