当前位置:  开发笔记 > 编程语言 > 正文

为什么C#构造函数不能推断类型?

如何解决《为什么C#构造函数不能推断类型?》经验,为你挑选了3个好方法。

为什么构造函数不支持类型推断,就像通用方法一样?

public class MyType
{
   private readonly T field;
   public MyType(T value) { field = value; }
}

var obj = new MyType(42); // why can't type inference work out that I want a MyType?

虽然你可以用工厂类解决这个问题,

public class MyTypeFactory
{
   public static MyType Create(T value)
   {
      return new MyType(value);
   }
}
var myObj = MyTypeFactory.Create(42);

构造函数不支持类型推断是否存在实际或哲学原因?



1> Eric Lippert..:

有没有一个哲​​学上的原因,为什么构造函数不能支持类型推断?

不,当你有

new Foo(bar)

然后我们可以在范围内识别所有称为Foo的类型,而不管通用arity,然后使用修改的方法类型推断算法对每个类型执行重载解析.然后,我们必须创建一个"更好"算法,该算法确定两个类型中具有相同名称但不同通用arity的两个适用构造函数一个是更好的构造函数.为了保持向后兼容性,非泛型类型的ctor必须始终获胜.

是否有一个实际的原因,为什么构造函数不能支持类型推断?

是.即使该功能的好处超过其成本 - 这是相当大的 - 但这还不足以实现功能.这个功能不仅必须是一个净赢,它必须是一个巨大的净胜利,相比我们可能投资的所有其他可能的功能.它还必须比花费时间和精力修复bug,性能更好工作,以及我们可以付出努力的其他可能领域.理想情况下,它必须适合发布的"主题".

此外,正如您正确指出的那样,通过使用工厂模式,您可以获得此功能的好处,而无需实际拥有该功能.易于使用的变通方法使得功能实现的可能性降低.

此功能已在很长一段时间内列在可能的功能列表中.它实际上从未在列表中足够高的地方实现.

2015年3月更新

建议的功能使其足够接近C#6列表顶部的指定和设计,但随后被剪切.


它仍然有点奇怪和不一致,IMO一致地实现功能的语言优势.但那只是我的个人意见.
语言一致性是一个优先事项,但与更实际的问题相比,它是一个低优先级.我向你们保证,我们有一个列表,比你用一句话描述的特征更长.如果我们目前的预算是目前预算的二十倍,我们仍然不希望实施该清单上的所有内容!相信我,你不会想要使用一种可以添加所有可能添加的功能的语言.我们非常谨慎地选择如何花费有限的精力来为客户提供最大的价值.
@Triynko:哦天哪,C#编译器未能做出各种可能的推论.例如,`class B {public virtual void M ()其中U:T {}}类D:B {public override void M (){}} ...(新的D()).M();` - 你和我可以使用我们的心理类型推断来知道唯一可能的类型参数是int,但C#编译器错过了这个技巧.我可以整天列出例子; 与F#相比,我们的类型推断非常弱.
或者`void M (T t1,T t2){} ... M(新的长颈鹿(),新的海龟());`你我可以推断代码的作者可能想要T是动物,但C#编译器没有说"长颈鹿和海龟共享一个共同的基类动物,因此它是T的最佳候选者".
@Triynko:或者`简短的M (out T y){...} ... var x = M(out x);`你和我可以推断唯一可能的返回类型是短的,因此x必须很短,因此T必须很短.但是如果在隐式类型的本地中存在*any*循环,则C#编译器会立即失效*.
@Triynko:我也喜欢.但是,"编译器对省略类型进行所有可能的推断"的目标显然是C#语言的非目标.实现这一目标需要付出巨大的代价; 这些资源可以更好地用于以其他方式添加用户价值.如果用F#编程,也许你会感觉更好?它具有比C#更高级的类型推断功能.
可笑的是,这是从C#6中删除的.解决方法是创建一个具有相同名称的类的静态非泛型版本,使用通用的`Create `方法支持类型推断来构造泛型版本的类.烦人的冗余代码可以通过此功能消除.比没有削减的许多其他功能更有用.
因此,泛型类型推断功能存在于C#4.0中......但不存在于构造函数中?我想这解释了为什么编译器抱怨我的构造函数调用我的TempIDTable 泛型类时,我认为它会根据我传递的类型推断T. 构造函数参数是List ,我认为将List 传递给调用将允许它推断T的类型,但我得到"使用泛型类型'TempIDTable '需要1个类型的参数'.这看起来很简单,我很惊讶它不会推断出类型.
这个缺少的功能使得很难将代码转换为使用泛型,因为我对这个构造函数有很多调用,比如"using(TempIDTable table = new TempIDTable(sql_connection,typed_list_of_ints_or_longs_etc))..."我必须手动返回,识别列表的类型并显式设置泛型类型参数.使用工厂模式的替代方法也需要更改,因此这对我们没有帮助.如果泛型类型可以如此透明地使用,我会非常好必须指定我传递给它的参数值之外的类型.
根据这篇文章,该功能似乎已经存在并且正在以某种方式工作:http://stackoverflow.com/a/45728/88409。就我个人而言,我宁愿具有完整,一致且定义明确的功能(类型推断...这样,如果可以从参数中推断出类型名称,无论如何您都无需编写类型名称类型)或根本不执行任何操作,仅仅是因为它会在某些情况下起作用,而在其他情况下却无法起作用,仅是因为它引起了混乱,引起了我的希望,感到惊讶,花了很多时间寻找答案,解释,哲学,等等
@Triynko:随意将评论传递给C#的设计师;与对四年没有在C#团队工作的人所写的“已有6年历史的问题”发表评论相比,这可能会更有效地利用您的时间。您可以在他们的github项目论坛上找到C#设计人员。

2> PostMan..:
public class MyType 
{ 
   private readonly T field; 
   public MyType(T value) { field = value; } 
} 

他们可以,没有必要再次告诉构造函数"T是什么",因为你已经在课堂上已经完成了这一点.

你的工厂也是不正确的,你需要的public class MyTypeFactory不仅仅是public class MyTypeFactory- 除非你在MyType课堂上宣布工厂

编辑更新:

那么,42是长,短,是int还是其他什么?

假设您有以下内容

class Base
{
   public virtual void DoStuff() { Console.WriteLine("Base"); }
}

class Foo : Base
{
   public override void DoStuff() { Console.WriteLine("Foo");  }
}

然后你做到了这一点

var c = new Foo();

var myType = new MyType(c);

你期望foo被使用,还是base?我们需要告诉编译器代替使用什么T

当你真的想要打字 base

因此

var myType = new MyType(c);


@PostMan:你不同意的答案部分是你的工厂是不正确的,你需要`public class MyTypeFactory `而不仅仅是'public class MyTypeFactory` - 除非你声明工厂里面的` MyType`class 实际上,正确的问题是`MyTypeFactory.Create `就像现在的问题一样,而不是你所说的需要的'MyTypeFactory .Create`.使用`MyTypeFactory .Create`会阻止类型推断,因为无法推断出在成员引用运算符`.`之前出现的泛型参数,方法上的那个参数可以.
编译器无法推断出类型,因为可能有多个构造函数.为了扩充你的例子,当`MyType(double)`存在时,编译器如何知道要调用哪个构造函数?

3> Kirk Woll..:

泛型类型推断不能像你希望的那样对构造函数起作用的主要原因是因为当你声明的所有类都是"MyType "时,类"MyType"甚至不存在.请记住,同时拥有两者是合法的:

public class MyType {
}

public class MyType {
}

两者都是合法的.如果您确实声明了两者,并且它们都声明了冲突的构造函数,那么您将如何消除语法歧义?

推荐阅读
罗文彬2502852027
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有