[英]Type constraints in interface apply to base class
我有一个基类定义了这样的泛型方法:
public class BaseClass
{
public T DoSomething<T> ()
{ ... }
}
由于这个类是由第三方提供的,并没有附带接口,因此我定义了一个接口,用于定义该类中实际需要的方法。 这样我就可以得到松散的耦合,并且实际上可以用其他东西来交换第三方类。 对于此示例,请考虑以下接口:
public interface ISomething
{
T DoSomething<T> ()
where T : Foo;
}
如您所见,它定义了相同的方法,但也对类型参数应用了类型约束,该类型参数来自与此无关的其他一些要求。
接下来,我定义了BaseClass
的子类型,它也实现了ISomething
。 该类将用作接口背后的通常实现 - 而接口将是应用程序的其余部分将访问的内容。
public class Something : BaseClass, ISomething
{
// ...
}
由于BaseClass
的DoSomething
已经支持任何类型参数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
在我的实际应用程序中,我有泛型参数和返回值。
尝试使用组合而不是继承来实现Something
:
public class Something : ISomething
{
private readonly BaseClass inner = ...;
void DoSomething<T>() where T : Foo
{
inner.DoSomething<T>();
}
}
当然,给定的代码可以编译并安全运行:
当Something
实例被输入Something
或BaseClass
,编译器将允许T
任何类型,而当同一实例被输入为ISomething
,它将只允许继承Foo
类型。 在这两种情况下,您都可以照常进行静态检查和运行时安
实际上,上面的场景正是您明确实现ISomething
时会发生的情况。 那么让我们看看我们可以为当前的事态做出什么样的争论。
对于:
反对:
考虑到上述情况以及此事实并非日常情况,恕我直言会得出的结论很明确:这可能会很好,但它肯定不会让您不顾一切地实施它。
您可以使用下面的代码获得所需内容。 通过在接口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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.