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

本文关键字:内联 数组 不能 | 更新日期: 2023-09-27 17:50:58

想象一下你在某个地方有这个

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(我错过了什么,如果有办法,你会怎么做?

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

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

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

正如@hvd提到的,你可以在没有参数的情况下做到这一点 (..) ,我添加了参数,因为我认为它更具可读性。

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

您可以指定数据类型new string[]就像已经提到的其他答案一样。


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

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

只需使用new[]编译器就可以知道数据类型(".." (,在{..}之间,你想要什么(string(。本质部分是[],这意味着你想要一个数组。

您甚至无法使用 new[] 创建一个空数组。

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

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

这一行:

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

是等效数组创建表达式的简写(在 ILSpy 下(

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

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

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

第 7.6.10.4 节中介绍了 C# 语言规范中的数组创建表达式。

因此,仅此"{"a", "b", "c"}"而不在声明中使用没有任何意义。因此,您不能将其与扩展方法一起使用,因为扩展方法在数组上运行。

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

在@adricadar的回答中已经提到过,你可以做到:

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

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

我反驳了"为什么不"的问题,因为首先,答案几乎永远不会令人满意——你已经得到了答案"功能不是你想要的方式,因为规范没有说你想要它说什么",我想这不是一个特别令人满意的答案。其次,设计团队不必证明为什么世界不是你想要的样子;功能不是免费存在的,然后由语言设计;相反,功能必须首先证明,然后设计。

因此,让我们尝试使您的"为什么不"问题更加清晰。现有功能是"数组初始值设定项可以 (a( 在初始化中等于的右侧或 (b( 在数组类型的对象构造的右侧使用。 建议的功能是:"数组初始值设定项也可以用作表达式"。问题是"埃里克会对提议的功能提出什么批评?

我要提出的第一个批评是,不清楚表达的类型是什么。在变量初始值设定项中,您具有变量的类型,在对象创建表达式中,您具有对象的类型;从这两者中,我们可以推断出构造数组的类型。在没有任何提示的情况下,我们应该推断出什么类型?

在 C# 1.0 中,添加此功能时,该语言中总共进行了零类型推断。C#早期的设计原则是"没有惊喜",编译器不是"太聪明"。如果开发人员希望表达式属于特定类型,则该类型在表达式中应以某种方式明显。 当你说

new double[] { 1, 2, 3.4 }
很明显,应该

使用哪种类型。同样地

new Animal[] { cat, dog, null }

提议的功能违反了这一原则。表达式必须具有类型,但绝不清楚参数的类型是什么

M({cat, dog, null})

此外:假设我们有两个M重载,其中一个需要Animal数组,另一个需要IPet数组。 哪种M过载适用?其中一个转换比另一个更好吗? 元素的类型是CatDog;推断出一种甚至没有出现的类型有意义吗?这些都是设计团队必须考虑的问题,这些问题绝不是显而易见的答案。拟议的功能将我们在很短的时间内带入深水区。

现在,C# 3.0

解决了这个问题,因为 C# 3.0 添加了许多功能,编译器代表开发人员推断类型。 早期关于"无意外"和"简单规则"的原则与使 LINQ 工作所需的其他设计原则相冲突。您建议的功能是否应该添加到 C# 3.0 中?

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

new[] { x, y, z }

使用算法推断数组的类型:获取具有类型的元素的表达式,确定其中哪种类型是所有其他表达式都可以转换为的唯一最通用类型,如果存在此类类型,请选择该类型。否则产生错误,

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

现在,如果你在 C# 3.0 时间范围内要求我批评提议的功能,我会指出 (1( C# 3.0 编译器已经处于整个版本时间表的严重危险中,所以我们不要为一个完全不必要的功能增加更多的设计、实现和测试负担,该功能为用户节省了次击键, (2( C# 3.0 还添加了集合初始值设定项:

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

为什么{10, 20, 30}应该自动成为数组? 为什么它不应该是一个List<int>? 还是其他许多类型中的任何一种?为什么偏向数组? 请记住,一旦我们选择为数组提供语法,我们就会永远坚持下去。它可能永远不会是其他任何东西,因此提议的功能不仅是不必要的,而且还阻止了未来可能出现的看似合理的功能。

总结:提出的功能直接违反了C#1.0的一些设计原则。它只会给 C# 3.0 增加不必要的负担。 在自 C# 3.0 以来的所有语言版本中,建议的功能没有很好的理由建议花费时间、精力和金钱而不是许多其他更有价值的功能。

因此,没有这样的功能。