Tag: 语言设计

为什么必须在静态类中定义C#扩展方法?

我知道C#扩展方法必须是静态的。 我不明白为什么这些扩展不能在非静态类或通用类中定义? 更新:我对此设计决策背后的原因感兴趣。

为什么定义C#规范(int.MinValue / -1)实现?

表达式int.Minvalue / -1导致根据C#规范实现定义的行为: 7.8.2分部运营商 如果左操作数是最小的可表示的int或long值而右操作数是-1,则发生溢出。 在已检查的上下文中,这会导致抛出System.ArithmeticException(或其子类)。 在未经检查的上下文中,它是实现定义的 ,是否抛出System.ArithmeticException(或其子类)或溢出未报告,结果值是左操作数的值。 测试程序: var x = int.MinValue; var y = -1; Console.WriteLine(unchecked(x / y)); 这会在.NET 4.5 32位上引发OverflowException ,但它不必。 为什么规范会保留结果实现定义? 这是反对这样做的情况: 在这种情况下,x86 idiv指令总是会导致exception。 在其他平台上,可能需要运行时检查来模拟它。 但是与该部门的成本相比,该检查的成本会很低。 整数除法非常昂贵(15-30个周期)。 这会打开兼容性风险(“一次写入无处可写”)。 开发者惊喜。 同样有趣的是,如果x / y是一个编译时常量,我们确实得到了unchecked(int.MinValue / -1) == int.MinValue : Console.WriteLine(unchecked(int.MinValue / -1)); //-2147483648 这意味着x / y可以根据所使用的句法forms具有不同的行为(并且不仅取决于x和y的值)。 这是规范允许的,但它似乎是一个不明智的选择。 为什么C#这样设计? 类似的问题指出了规范中的哪个确切行为是规定的,但它没有(充分)回答为什么语言是这样设计的。 不讨论替代选择。

为什么通过inheritance类型访问静态成员是有用的?

我很高兴C#不允许你访问静态成员,就像’他们是实例成员一样。 这避免了Java中的常见错误: Thread t = new Thread(..); t.sleep(..); //Probably doesn’t do what the programmer intended. 另一方面,它允许您通过’派生类型访问静态成员。 除了运算符(它可以让你免于编写演员表),我无法想到任何实际上有用的情况。 事实上,它积极鼓励错误,例如: // Nasty surprises ahead – won’t throw; does something unintended: // Creates a HttpWebRequest instead. var ftpRequest = FtpWebRequest.Create(@”http://www.stackoverflow.com”); // Something seriously wrong here. var areRefEqual = Dictionary.ReferenceEquals(dict1, dict2); 当我通过不熟悉的API搜索时,我个人不断地反复提出类似的错误(我记得从表达树开始;我在编辑器中点击BinaryExpression.并且想知道为什么地球上的IntelliSense提供MakeUnary作为选项)。 在我的(短视)意见中,此function: 不减少冗长; 程序员必须以某种方式指定类型名称(当访问当前类型的inheritance静态成员时,不包括运算符和大小写)。 鼓励上面提到的错误/误导性代码。 可以向程序员建议C#中的静态方法表现出某种“多态性”,而不是。 (次要)在重新编译时引入’沉默’,可能是无意的重新绑定可能性。 (国际海事组织,运营商是一个特殊情况,值得他们自己讨论。) […]

为什么C#不支持类/方法级别的const?

我一直想知道为什么C#不支持类或方法级别的const 。 我知道Jon Skeet长期以来一直希望支持不变性,并且我认为使用函数const的C ++语法可以帮助实现这一点。 通过在类级别添加const关键字,我们将获得全面支持。 现在,我的问题是,C#团队没有开发出这种支持的原因是什么? 我想可以通过编译时检查或通过属性创建所有内容,而无需更改CLR。 我不介意代码能够通过reflection覆盖const行为。 想象一下: const class NumberContainer { public int Number { get; } } ..这样的类只能在构造时填充,所以我们需要一个构造函数来接受一个int。 另一个例子是方法级别的const: public int AddNumbers(NumberContainer n1, NumberContainer n2) const { return n1.Number + n2.Number; } const级方法不应该能够改变它们自己的类中的状态或传递给它们的引用类型的实例。 此外,const级函数只能在其范围内调用其他const级函数。 我不确定lambdas和代表是否会使一切都太难(或不可能)实现,但我确信有更多语言和编译器设计经验的人可以告诉我。 正如Steve B在评论中指出的那样, readonly的存在使得事情变得更复杂,因为const和readonly在runtime期间接近相同,但是在编译时不能确定readonly值。 我想我们可以有const和readonly级别,但这可能太混乱了? 那么,没有实现这个的原因是什么? 可用性问题(理解C ++中的常量通常对新用户来说很难),语言设计问题(无法完成)或仅仅是优先级问题(不变性的时代 – 嗡嗡声已经结束)。

C#语言设计:`is`操作符内的方法组

我对C#语言的一些设计选择感兴趣。 C#规范中有一条规则允许使用方法组作为运算符的表达式: class Foo { static void Main() { if (Main is Foo) Main(); } } 上述条件总是错误的,因为规范说: 7.10.10是运营商 • 如果E是方法组或空文字,如果E的类型是引用类型或可空类型且E的值为null,则结果为false。 我的问题:允许在CLR中使用没有运行时表示的C#语言元素的目的/点/原因是什么,就像这样的“运行时”运算符中的方法组一样?

为什么在generics参数约束中强制执行某些排序?

在定义generics类型参数的约束时,我们必须将class()放在前面,将new()放在末尾。 为什么这样,为什么我不能按任何顺序放置约束? 除了class / struct之外,还有其他任何限制,最后是new()吗? 例: protected T Clone() where T : class, ICopyable, new()

为什么C#运算符重载必须是静态的?

为什么C#要求运算符重载是静态方法而不是成员函数(如C ++)? (也许更具体地说:这个决定的设计动机是什么?)

C#中的案例声明块级声明空间

有没有理由我错过了case语句中的块不被视为块级声明空间? 我尝试时不断收到错误(变量已经声明) case x: var someVariable = 42; break; case y: var someVariable = 40; break; 但我能做到 case x: try{var someVariable = 42;}catch{} break; case y: try{var someVariable = 40;}catch{} break; 如果C#允许通过语句,那就没有意义,但事实并非如此,我想不出你可以在case语句中声明变量并在该块之外使用它的场景。

C#:没有从Class 到Class 的转换

以下代码片段无法编译。 出现以下错误: 无法将类型’Container ‘隐式转换为’Container ‘ class BaseClass {} class ChildClass : BaseClass {} class Container where T : BaseClass {} class Program { static void Main() { // why doesn’t this work? Container obj = new Container(); } } 这是设计的吗? 如果是,那是什么原因?

为什么C#不允许字段初始化程序使用非静态字段?

为什么C#会允许这样做: public class MyClass { static int A=1; static int B=A+1; } 但是不允许( “字段初始值设定项不能引用非静态字段,方法或属性” )这个 public class MyClass { int A=1; int B=A+1; } 我认为这是保证(使用静态字段)顺序初始化的顺序,但它也可以在这里应用,如您所见: public class MyClass { int A=((Func)(delegate(){ Console.WriteLine (“A”); return 1;}))(); int B=((Func)(delegate(){ Console.WriteLine (“B”); return 2;}))(); int C=((Func)(delegate(){ Console.WriteLine (“C”); return 3;}))(); } void Main() { var a = new […]