12

我以前从未发布过这种性质的问题,所以如果它不适合 SO,请不要伤害我的感情,我会删除它。

为了让我关心的所有内容尽可能靠近左边距,我一直希望我能写出类似的东西:

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

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

4

6 回答 6

25

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

是的我们有。几年前我们考虑过。作为这种说法的证据,请参阅我文章的最后一段:

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

设计团队的共识是,这是一个“值得拥有”的功能,但还不够引人注目,以至于值得为设计、实施、测试、记录和维护该功能付出可观的成本。

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

但是,如果您可以将建议的语法与促进不可变类型的简洁声明的其他语言功能结合起来,那么建议的语法会变得特别好;如果我们在假设的未来版本的语言中做这样的功能,那么你提出的语法就会变得更有说服力。

我进一步指出,我们通常会抵制需要从“外部”到“内部”进行推断的特征;我们更喜欢那种由内而外的信息流。例如考虑这个问题:

M(new(blah));

假设 M 有两个重载,一个采用 C,另一个采用 D。那是“new 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( cn )。

C# 确实以这种方式对 lambda 进行推理,相信我,这是编译器中最难实现高性能和正确的部分之一。我们并不急于向构造函数添加类似的功能。如果我们要添加这种语法,它可能仅限于通过分析变量声明或赋值表达式的左侧明确知道类型的情况。

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

于 2011-04-25T16:52:20.987 回答
2

它从左侧向后推断表达式。如果表达式不是微不足道的,那会很快变得丑陋。

您可以通过几乎总是查看表达式本身来理解表达式的作用(除了一些 lamda 类型推断),而这对于您的语法是不可能的。使用 lamdas 的增益相当大,因此复杂的推理对于 lamdas 来说是一个很好的折衷方案,但是为这样一个微不足道的特征添加复杂性对于简单的变量初始化来说是一个糟糕的折衷方案。

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

于 2011-04-25T16:50:23.557 回答
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);

可憎、好奇还是有用的技术?你决定。

于 2011-04-25T18:37:21.327 回答
1

现在有一个支持的提案和这个特性的实现。我们很可能会在 C# 8.0 中看到它。

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

于 2018-11-13T15:47:35.003 回答
0

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

var dataEntities = new DataService1.DataEntities(constructorArg1, ...)
于 2011-04-25T16:47:28.987 回答
0

还有怎么样:

DataType dt;

意思相同:

DataType dt = new DataType();

进而:

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

是相同的:

DataType dt = new DataType(){ ParamOne = 1, ParamTwo =2 };
于 2011-04-25T16:54:08.513 回答