C#规范(团队?委员会?)是否曾考虑过这种对象创建语法?

时间:2011-04-25 16:45:08

标签: c# syntax language-design language-specifications

我之前从未发过这种性质的问题,所以如果它不适合SO,那就不要伤害我的感情太糟糕了,我会删除它。

为了尽可能保持我所关心的一切尽可能接近左边距,我一直希望能写下这样的内容:

DataService1.DataEntities dataEntities = new(constructorArg1, ...)

我认为另一个原因是我喜欢通过使用var获得的额外屏幕空间,当类型已经出现在作业的右侧时,但是我的大脑有太多年来在左侧寻找类型。再说一遍,被困在我的方式并不是一个很好的理由,希望有一个规范...

6 个答案:

答案 0 :(得分:24)

  

C#设计委员会是否考虑过这种对象创建语法?

是的,我们有。几年前我们考虑过它。作为此声明的证据,请参阅我的文章的最后一段:

http://blogs.msdn.com/b/ericlippert/archive/2009/01/26/why-no-var-on-fields.aspx

设计团队的共识是,这是一个“很好的”功能,但不足以引起设计,实施,测试,记录和维护功能的相当大的成本。

我还注意到,我链接到的博客条目的评论对该功能非常不利;似乎很多人发现语法没有吸引力。这也是反对做这个功能的要点。

但是,如果您可以将其与其他语言功能相结合,以促进简单的不可变类型声明,那么所提出的语法会变得特别好;如果我们在假设的未来版本的语言中做这样的功能,那么你提出的语法会变得更加引人注目。

我进一步注意到,我们通常会抵制需要从“外部”到“内部”进行推理的功能;我们更喜欢从内到外的类型信息流。考虑一下这个问题:

M(new(blah));

假设M有两个重载,一个采用C,一个采用D.是“新C(blah)”还是“new D(blah)”?它可能是。现在我们要分析两者!如果他们都工作,那么我们必须弄清楚哪个更好。

情况变得更糟。假设你有

M(new(new(blah)));

其中M取C和D,C有两个构造函数取E或F,D有两个构造函数取G和H.其中:

M(new C(new E(blah)));
M(new C(new F(blah)));
M(new D(new G(blah)));
M(new D(new H(blah)));
选择

,为什么?

当你从外到内推理时,你会很快进入“组合爆炸”,在这里,分析的病例数在嵌套深度变为O(c n )。

C#以这种方式为lambdas做出推理,并且这是编译器中最难以使性能和正确的部分之一,相信我。我们并不急于为构造函数添加类似的功能。如果我们要添加这种语法,它可能仅限于通过分析变量声明或赋值表达式的左侧明确知道类型的场景。

(与往常一样,我注意到Eric对于没有时间表或预算的未宣布且完全虚构的产品中假设的未来语言特征的思考仅用于娱乐目的,不应被视为对任何特定未来产品的承诺任何特定的功能集。)

答案 1 :(得分:2)

它从左侧向后推断到表达式。如果表达非常微不足道,那就会很快变得难看。

你可以通过几乎总是查看表达式本身来理解表达式的作用(除了一些lamda类型推断),这对于你的语法是不可能的。对于lamdas,增益非常大,因此复杂的推理对于lamdas来说是一个很好的权衡,但是为简单的变量初始化添加这种复杂功能是一个不好的平衡。

你可以特殊情况“赋值给变量,其中右边的最外面的表达式是new表达式。”对我来说听起来非常不优雅。特别是因为var功能已经实现了非常相似的功能,同时更加灵活。

答案 2 :(得分:2)

如果要创建与用于存储它的成员相同类型的对象而不必重复类型名称,则可以使用“Stockton new”。缺点是您必须在初始化中重复成员名称。这是它的外观:

class Program
    {
       private static T New<T>(out T item) where T : new()
       {
           item = new T();

           return item;
       }

       static Dictionary<Int32, Int32> _member = New(out _member);

       static void Main(string[] args)
       {
           Dictionary<Int32, Int32> local = New(out local);
       }
}

此外,我们可以扩展此方法,为相应的接口创建具有几个简单重载的具体类:

public static IDictionary<TKey, TValue> New<TKey, TValue>(out IDictionary<TKey, TValue> item)
{
     item = new Dictionary<TKey, TValue>();

     return item;
}

public static IList<T> New<T>(out IList<T> item)
{
     item = new List<T>();

     return item;
}

现在你可以这样写:

IDictionary<Int32, Int32> local = New(out local);

憎恶,好奇或有用的技巧?你决定了。

答案 3 :(得分:1)

现在有一个备受鼓舞的提案,并且正是此功能的实现。我们可能会在C#8.0中看到它。

请参见https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-new.md

答案 4 :(得分:0)

不确定,但如果你想把事情放在左边,你可以改用:

var dataEntities = new DataService1.DataEntities(constructorArg1, ...)

答案 5 :(得分:0)

还有如何:

DataType dt;

意思相同:

DataType dt = new DataType();

然后:

DataType dt = { ParamOne = 1, ParamTwo = 2 };

与:

相同
DataType dt = new DataType(){ ParamOne = 1, ParamTwo =2 };