【发布时间】:2015-10-21 09:41:03
【问题描述】:
默认情况
让我们假设以下示例性问题 - 我想创建一个方法,该方法将简单地输出任何 List<> 集合中的元素数量。
我用一种方法创建了以下静态类:
public static class MyClass
{
public static void MyMethod<T>(T obj) where T : List<int> // sort of pointless, yes
{
Console.WriteLine(obj.Count);
}
}
注意T 是List<int> 的子类。现在,我可以打电话了:
List<int> li = new List<int>();
MyClass.MyMethod<List<int>>(li);
现在,IDE 告诉我“类型参数规范是多余的”。它可以从用法中推断出类型:
List<int> li = new List<int>();
MyClass.MyMethod(li); // OK. li is List<int>, type argument is not required
一般情况
据你所知,我想输出 any 类型的List 的计数。像这样的东西会很棒:
public static void MyComplexMethod<T>(T obj) where T : List<any>
{
Console.WriteLine(obj.Count);
}
但是,它的语法不正确。我必须实现以下方法:
public static void MyComplexMethod<T1, T2>(T1 obj) where T1 : List<T2>
{
Console.WriteLine(obj.Count);
}
现在,在不显式描述类型的情况下调用此方法会产生错误“无法从用法中推断方法的类型参数”:
List<int> li = new List<int>();
MyClass.MyComplexMethod(li); // error
MyClass.MyComplexMethod<List<int>>(li); // error
MyClass.MyComplexMethod<List<int>, int>(li); // OK
MyClass.MyComplexMethod<List<double>, double>(new List<double>()); // OK
MyClass.MyComplexMethod<List<string>, string>(new List<string>()); // OK
// error. The type must be convertible in order to use...So, compiler knows it
MyClass.MyComplexMethod<List<string>, double>(new List<string>());
但是,对我来说,类型似乎应该可以从使用中推断出来。我提供List<int> - T1 是List<int> 而T2 是int,显然。为什么编译器不能做到这一点?实现理想行为的最合理方法是什么 (where T : List<any>)?
真实案例
如果有人只是想知道我为什么需要这个。实际上,当我尝试实现 WCF 代理包装器时,我偶然发现了这种情况,如下所示:
public static void Call<TServiceProxy, TServiceContract>(Action<TServiceProxy> action)
where TServiceProxy : ClientBase<TServiceContract>, new()
where TServiceContract : class
{
TServiceProxy serviceProxy = new TServiceProxy();
try
{
action(serviceProxy);
serviceProxy.Close();
}
catch (Exception ex)
{
serviceProxy.Abort();
// Log(ex);
throw;
}
}
Service.Call<EchoServiceClient>(x => {
int v = DateTime.Now.ToString();
x.Echo(v);
}); // not working
Service.Call<EchoServiceClient, IEchoService>(x => {
int v = DateTime.Now.ToString();
x.Echo(v);
}); // not convenient, pointless. EchoServiceClient inherits from ClientBase<IEchoService>
没有where TServiceProxy : ClientBase<TServiceContract>,我将无法做到serviceProxy.Abort()。同样,where TServiceProxy : ClientBase<any> 将是一个很好的解决方案,因为实际上 TServiceContract 并不重要 - 它仅用于 where 约束。
【问题讨论】:
-
你可以使用一个接口然后扩展类型,然后你可以像
ClientBase<SomInterface>那样对接口进行约束 -
使用
IList而不是List<any> -
@M.kazemAkhgary 太好了,谢谢!对于
List<>,问题已解决。真实案例呢?我还没有找到像IClientBase这样的东西。 -
你试过了吗?
public static void Call<TServiceContract>(Action<ClientBase<TServiceContract>> action) where TServiceContract : class -
@Henrik 那么,我将无法实例化
TServiceProxy proxy = new TSeviceProxy();
标签: c# .net generics inheritance