gpt4 book ai didi

c# - 为什么不能为泛型类型推断类型参数?

转载 作者:行者123 更新时间:2023-11-30 12:24:40 25 4
gpt4 key购买 nike

默认情况

让我们假设以下示例性问题 - 我想要创建一个方法,该方法将简单地输出任何 List<> 中的元素数量。收藏.
我用一种方法创建了以下静态类:

public static class MyClass
{
public static void MyMethod<T>(T obj) where T : List<int> // sort of pointless, yes
{
Console.WriteLine(obj.Count);
}
}

请注意 TList<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

一般情况

据你所知,我想输出 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约束条件。

最佳答案

您应该考虑您对该类型的实际要求是什么。

在你的情况下,你想做什么?您希望能够执行 action在您在该方法中创建的客户端上。该客户端是您作为泛型类型参数传递的类型。你需要知道这是一个ClientBase<something>吗?为了执行 Action ?没有。

你还对这个对象做了什么?您打开和关闭 channel 。这些是由 ICommunicationObject 确保的操作哪个ClientBase<T>实现。

这就是您的全部要求。所以你想有以下约束:

  • 能够创建该类型的对象。
  • 实现类型 ICommunicationObject这样您就可以打开/关闭 channel 。

因此您的方法可能如下所示:

public static void Call<T>(Action<T> action)
where T: ICommunicationObject, new()
{
T serviceProxy = new T();
try
{
action(serviceProxy);
serviceProxy.Close();
}
catch (Exception ex)
{
serviceProxy.Abort();
throw;
}
}

最后,回答你为什么编译器不能自动解决这个问题:如果你有泛型类型参数,有两种可能性。要么编译器能够推断出所有 类型参数,在这种情况下您可以将它们省略,要么编译器无法推断出所有参数,在这种情况下您需要全部指定它们。毕竟Foo<X>()Foo<X, Y>()是不同的方法签名,所以如果后者也允许 Foo<X>() , 这将是模棱两可的。

至于为什么编译器不能在您的情况下推断出所有 类型参数,这仅仅是因为没有为类型推断评估约束给定的类型参数之间的关系。

关于c# - 为什么不能为泛型类型推断类型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33255841/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com