不能在c#中使用“内联”数组?

想象一下,你有这个地方

public static T AnyOne<T>(this T[] ra) where T:class { int k = ra.Length; int r = Random.Range(0,k); return ra[r]; } 

甚至只是这个

 public static string OneOf(this string[] strings) { return "a"; } 

那么,你当然可以做到这一点…

 string[] st = {"a","b","c"}; string letter = st.AnyOne(); 

…这是伟大的。 但。 看来你不能这样做:

 string letter = {"a","b","c"}.AnyOne(); 

或者也许这个

 string letter = ( {"a","b","c"} ).AnyOne(); 

或其他我试过的东西。

事实上(1)为什么不能这样做呢? (2)我错过了什么,如果有办法,你会怎么做?

您必须先使用new[]创build数组。

 string letter = (new[] {"a","b","c"}).AnyOne(); 

正如@ hvd提到的,你可以做这个没有parantheses (..) ,我加了parantheses,因为我认为它更可读。

 string letter = new[] {"a","b","c"}.AnyOne(); 

你可以指定数据typesnew string[]作为其他答案已经提到。


你不能只做{"a","b","c"} ,因为你可以把它看作是填充数组的方法,而不是创build它。

另一个原因是编译器会感到困惑,不知道要创build什么,例如一个string[]{ .. }或一个List<string>{ .. }

使用new[]编译器可以通过数据types".." ),在{..}之间,你想要什么( string )。 基本部分是[] ,这意味着你想要一个数组。

你甚至不能用new[]创build一个空的数组。

 string[] array = new []{ }; // Error: No best type found for implicity-typed array 

(1)为什么不能这样做? {"a","b","c"}.AnyOne();

这一行:

 string[] st = {"a","b","c"}; 

是一个等价的数组创buildexpression式 (在ILSpy下)

 string[] st = new string[] {"a","b","c"}; 

这个string[] st = {"a","b","c"} 只能在声明时使用,不能在其他地方使用,甚至不能使用:

 string[] st; st = {"a", "b", "c"}; //Error 

C#语言规范中的“数组创build”expression式在第7.6.10.4节中进行了解释。

所以这个"{"a", "b", "c"}"在宣言中没有用处,就没有任何意义。 因此你不能在你的扩展方法中使用它,因为你的扩展方法在一个数组上运行。

(2)我错过了什么,如果有办法,你会怎么做?

在@ adricadar的答案中已经提到,你可以这样做:

 (new[] {"a","b","c"}).AnyOne(); 

要么

 (new string[] {"a","b","c"}).AnyOne(); 

我推回了“为什么不”的问题,因为首先,答案几乎不会令人满意 – 你已经得到了答案“function不是你想要的方式,因为规范没有说你想要说什么” ,我想这不是一个特别满意的答案。 其次,devise团队不必certificate为什么这个世界不是你想要的; function不是免费的,然后用语言来devise; 相反,function必须首先certificate,然后devise。

所以让我们试着让你的“为什么不”问题更加清晰。 现有的特性是“一个数组初始值设定项可以用于(a)在初始化的等号右边,或者(b)在数组types的对象结构的右边。 build议的function是:“一个数组初始值设定项也可以用作expression式”。 问题是“Eric对这个提议的特征有什么批评?”

我要提出的第一个批评是不清楚expression的types是什么。 在一个variables初始化器中你有variables的types,在一个对象创buildexpression式中你有这个对象的types; 从这两个我们可以推断出构造数组的types。 没有提示,我们应该推断什么types?

在C#1.0中,当添加了这个特性时,在这个语言中总共有零个types的推断。 C#初期的一个devise原则是“没有意外”,编译器不是“太聪明”。 如果开发者希望expression式是一个特定的types,那么这个types在expression式中应该是明显的。 当你说

 new double[] { 1, 2, 3.4 } 

很清楚什么types是打算。 同样

 new Animal[] { cat, dog, null } 

build议的function违反了这个原则。 expression式必须有一个types,但是它决不清楚这个参数的types是什么

 M({cat, dog, null}) 

而且:假设我们有两个M重载,其中一个需要一个Animal数组,另一个需要一个IPet数组。 M哪个超载适用? 其中一个转换比另一个更好吗? 元素的types是Dog ; 推导出一种甚至没有出现的types是否合理? 这些都是devise团队必须考虑的问题,而这些问题绝非明显的答案。 提出的特点使我们以相当短的时间进入深海。

现在,C#3.0解决了这个问题,因为C#3.0在编译器为开发人员推断types时添加了许多function。 早期有关“不出意外”和“简单规则”的原则与LINQ工作所需的其他devise原则相冲突。 你提出的function是否已经添加到C#3.0中?

本来可以的。 C#3.0中实际添加的function是:

 new[] { x, y, z } 

使用以下algorithm推断数组的types:对具有types的元素采用expression式,确定哪些types是所有其他expression式可以转换的唯一最一般types,如果存在,请select该types。 否则会产生错误,

该function可以进一步放宽,使new[]可选。 这没有完成。

现在,如果你问我在C#3.0的时间段来批评这个提议的特性,我会指出:(1)C#3.0编译器已经在严重危害整个版本的时间安排,所以我们不要再添加(2)C#3.0还增加了集合初始值设定项:

 new List<int>() { 10, 20, 30 } 

为什么要{10, 20, 30}自动成为一个数组 ? 为什么不应该是一个List<int> ? 或者其他任何一种types? 为什么对数组的偏见? 请记住, 一旦我们select提供数组的语法,我们就永远坚持下去 。 它可能永远不会是别的,所以提议的function不仅是不必要的,而且还防止了未来可能的function似乎是合理的。

总结:提出的function直接违反了C#1.0的一些devise原则。 它只增加了C#3.0不必要的负担。 在C#3.0以来的所有语言版本中,build议的function都没有什么好的build议来推荐花费时间,精力和金钱,而不是其他更有价值的function。

所以没有这个function。