我有一个基类,它定义了这样的泛型方法:
public class BaseClass
{
public T DoSomething<T> ()
{ ... }
}
由于此类是由第三方提供的,并且没有接口,因此我定义了一个接口,用于定义该类中实际需要的方法。这样我就可以得到松散的耦合,并且实际上可以用其他东西来交换第三方类。对于此示例,请考虑以下界面:
public interface ISomething
{
T DoSomething<T> ()
where T : Foo;
}
如您所见,它定义了相同的方法,但也对类型参数应用了类型约束,该约束来自与此无关的其他一些要求。
接下来,我定义了BaseClass
的子类型,它也实现了ISomething
。该类将用作接口背后的通常实现 - 而接口将是应用程序的其余部分将访问的内容。
public class Something : BaseClass, ISomething
{
// ...
}
由于DoSomething
中的BaseClass
已经支持任何类型参数T
,因此它应该特别支持类型参数,该参数是Foo
的子类型。因此可以预期BaseClass
的子类型已经实现了接口。但是我收到以下错误:
方法'BaseClass.DoSomething()'的类型参数'T'的约束必须匹配接口方法'ISomething.DoSomething()'的类型参数'T'的约束。请考虑使用显式接口实现。
现在,我有两种可能性;第一个是做错误建议并明确地实现接口。第二种是使用new
隐藏基础实现:
// Explicit implementation
T ISomething.DoSomething<T> ()
{
return base.DoSomething<T>();
}
// Method hiding
public new T DoSomething<T>()
where T : Foo
{
return base.DoSomething<T>();
}
两者都有效,尽管我可能更喜欢第二种解决方案来保持方法本身可以访问。但是它仍然留下以下问题:
为什么我必须在基类型使用less-strict(read:none)类型约束实现它时重新实现该方法?为什么该方法需要完全按原样实现?
编辑:为了让方法更具意义,我将返回类型从void
更改为T
。在我的实际应用程序中,我有泛型参数和返回值。
答案 0 :(得分:3)
尝试使用合成而不是继承来实现Something
:
public class Something : ISomething
{
private readonly BaseClass inner = ...;
void DoSomething<T>() where T : Foo
{
inner.DoSomething<T>();
}
}
答案 1 :(得分:1)
当然,可以编译并安全地运行给定的代码:
当Something
实例的类型为Something
或BaseClass
时,编译器将允许T
的任何类型,而同一实例的类型为ISomething
它只允许继承Foo
的类型。在这两种情况下,您都可以像往常一样获得静态检查和运行时安全性。
事实上,上面的场景完全当你明确地实现ISomething
时会发生什么。那么让我们看看我们可以为当前做什么和反对当前做什么现状。
有关:
反对:
考虑到上述以及此事实并非日常情况,恕我直言得出的结论很清楚:这个可能很好,但它肯定不值得外出你的实施方式。
答案 2 :(得分:1)
您可以使用下面的代码获得所需内容。通过在接口defenition中包含type参数,您可以使其协变,这似乎满足编译器。 Base
类保持不变,您可以隐藏Base
实现并使用单个方法实现接口。
class Program
{
static void Main()
{
var something = new Something<Foo>();
var baseClass = (BaseClass)something;
var isomething = (ISomething<Foo>)something;
var baseResult = baseClass.DoSomething<Bar>();
var interfaceResult = isomething.DoSomething<Bar>();
var result = something.DoSomething<Bar>();
}
}
class Foo
{
}
class Bar : Foo
{
}
class BaseClass
{
public T DoSomething<T>()
{
return default(T);
}
}
interface ISomething<out T> where T : Foo
{
T DoSomething<T>();
}
class Something<T> : BaseClass, ISomething<T> where T : Foo
{
public new T DoSomething<T>()
{
return default(T);
}
}
或者,如果您确实不想在实例化中指定Foo
class Program
{
static void Main()
{
var something = new Something();
var baseClass = (BaseClass)something;
var isomething = (ISomething)something;
var baseResult = baseClass.DoSomething<Bar>();
var interfaceResult = isomething.DoSomething<Bar>();
var result = something.DoSomething<Bar>();
}
}
class Foo
{
}
class Bar : Foo
{
}
class BaseClass
{
public T DoSomething<T>()
{
return default(T);
}
}
interface ISomething
{
T DoSomething<T>;
}
interface ISomething<S> : ISomething where S : Foo
{
new R DoSomething<R>() where R : Foo;
}
class Something : BaseClass, ISomething
{
public new T DoSomething<T>()
{
return default(T);
}
}