我正在研究一个简单的数学库用于教育目的,我已经实现了一个struct代表Rational Number的数学库.显示结构核心字段的非常基本的代码是:
public struct RationalNumber
{
private readonly long numerator;
private readonly long denominator;
private bool isDefinitelyCoprime;
private static RationalNumber zero = 0;
public RationalNumber(long numerator, long denominator)
{
this.numerator = numerator;
this.denominator = denominator;
this.isDefinitelyCoprime = false;
}
...
}
Run Code Online (Sandbox Code Playgroud)
目前我正在实现一个RationalMatrix,你可能已经猜到,它将由RationalNumber类型元素组成.
我正在创建静态构建器的有用矩阵是Identity矩阵.代码如下:
public static RationalMatrix GetIdentityMatrix(int dimension)
{
RationalNumber[,] values = new RationalNumber[dimension, dimension];
for (int i = 0; i < dimension; i++)
values[i, i] = 1;
return new RationalMatrix(values);
} …Run Code Online (Sandbox Code Playgroud) 我希望您就以下主题发表意见:
想象一下,我们有一个方法负责实现一个特定的目的,但要做到这一点,它需要大量本地范围的对象的支持,其中许多实现IDisposable.
MS编码标准规定,当使用IDisposable不需要"生存"方法范围的本地对象(不会返回或不会被分配给某些更长寿的状态信息object)时,您应该使用该using构造.
问题是,在某些情况下,您可以获得嵌套的"地狱" using块:
using (var disposableA = new DisposableObjectA())
{
using (var disposableB = new DisposableObjectB())
{
using (var disposableC = new DisposableObjectC())
{
//And so on, you get the idea.
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您使用的某些对象派生自公共库或实现实现的公共interface,则可以以某种方式缓解此问题IDisposable.当然,这需要在需要对象的真实类型时必须投射所述对象.有时,只要铸件的数量不会失控,这是可行的:
using (var disposableA = new DisposableObjectA())
{
using (DisposableBaseObject disposableB = new DisposableObjectB(),
disposableC = new DisposableObjectC)
{
using (var disposableD = new DisposableObjectD())
{
//And so on, you get …Run Code Online (Sandbox Code Playgroud) 好的,请考虑以下代码:
private const int THRESHHOLD = 2;
static void Main(string[] args)
{
string hello;
if (THRESHHOLD > 1) return;
Console.WriteLine(hello);
}
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,这段代码没有抛出" 使用未分配的局部变量'hello' "编译时错误.它只是发出警告" 检测到无法访问的代码 ".
即使代码无法访问,它仍然是编译时错误,我认为正确的做法是抛出编译时错误.如果我要做以下事情:
private const int THRESHHOLD = 2;
static void Main(string[] args)
{
string hello;
if (THRESHHOLD > 1) return;
hello.LMFAO();
}
Run Code Online (Sandbox Code Playgroud)
果然,我得到一个" '字符串'不包含'LMFAO'的定义,并且没有扩展方法'LMFAO'接受类型'string'的第一个参数可以找到(你是否缺少using指令或汇编引用? ) "编译时错误.
为什么使用未分配的变量不一样?
编辑改变了const变量,使其不那么分散注意力.我想许多人都忽略了问题的重点,这取决于哪种情况,编译时错误优先于无法访问的代码.
在C#中,语言中没有内置的交换概念.那就是我Vector为例子定义一个简单的类:
public struct Vector
{
private readonly double x, y, z;
...
public static Vector operator +(Vector v, double d) {...}
}
Run Code Online (Sandbox Code Playgroud)
我仍然需要定义对称运算符,+(double d, Vector v)否则表单的任何表达式2.1 * v都会在动态方案中在运行时产生编译错误或失败.
我的问题有两个方面:首先,是否有任何语言可以定义交换运算符而无需定义两种可能的操作数组合?换句话说,是否有任何语言意识到交换性本身的概念?第二,它是否曾在C#中被考虑并被废弃,因为它真的只是语法糖,以避免一些额外的击键,并没有真正增加语言的所有丰富性(并且很可能需要一个额外的保留字)?
这个问题是Cristi Diaconescu关于this在C#中访问字段初始化程序的非法性的扩展.
这在C#中是非法的:
class C
{
int i = 5;
double[] dd = new double[i]; //Compiler error: A field initializer cannot reference the non-static field, method, or property.
}
Run Code Online (Sandbox Code Playgroud)
好的,所以合理解释为什么这是非法的,其中包括Eric Lippert:
简而言之,在构造函数体运行之前访问接收器的能力是边缘效益的特征,这使得编写错误程序更容易.因此,C#语言设计者完全禁用它.如果需要使用接收器,则将该逻辑放在构造函数体中.
此外,C#规范非常简单(直到某一点):
实例字段的变量初始值设定项无法引用正在创建的实例.因此,在变量初始化程序中引用它是一个编译时错误,因为变量初始化程序通过简单名称引用任何实例成员是编译时错误.
所以我的问题是:" 通过一个简单的名字 "是什么意思?
是否存在合法的替代机制?我确信规范中几乎每个单词都有一个非常具体的原因,那么通过简单的名称将这个特定代码的非法性限制为引用的原因是什么?
编辑:我没有把我的问题措辞得太好.我不是要求" 简单名称 " 的定义,我问的是将非法性限制在特定情况的原因.如果以任何方式引用任何实例成员始终是非法的,那么为什么要如此狭窄地指定呢?如果不是,那么什么机制合法呢?
基于这个有趣的问题:在Nicholas Carey的回答中提到的添加int和uint以及使用常量折叠进行操作时,我偶然发现了编译器看似不一致的行为:
请考虑以下代码段:
int i = 1;
uint j = 2;
var k = i - j;
Run Code Online (Sandbox Code Playgroud)
这里编译器正确解析k为long.这种特殊行为在规范中有明确定义,如前面提到的问题的答案中所解释的那样.
让我感到惊讶的是,在处理文字常量或常量时,行为会发生变化.阅读Nicholas Carey的回答我意识到行为可能不一致所以我检查并确定:
const int i = 1;
const uint j = 2;
var k = i - j; //Compile time error: The operation overflows at compile time in checked mode.
k = 1 - 2u; //Compile time error: The operation overflows at compile time in …Run Code Online (Sandbox Code Playgroud) 可能重复:
您何时使用代码块?
好吧,这可能是一个愚蠢的问题,我可能会遗漏一些明显的东西但是当我慢慢学习C#时,这已经让我唠叨了一段时间了.
以下代码显然编译得很好:
public void Foo()
{
{
int i = 1;
i++;
}
{
int i = 1;
i--;
}
}
Run Code Online (Sandbox Code Playgroud)
我知道{}块可以用于范围界定.问题是你为什么要这样做?这个功能解决了哪些问题?
我在使用它们时没有任何害处,除非它确实增加了一个更令人困惑的代码,因为与那些"绑定"流控制,迭代等相比,这些范围可能更容易被忽略.
这是基于这个问题,在我看来编译器中存在语言故障或缺失警告.我的理由是is将始终返回true以下类型的表达式:
int i;
if (i is var j) ....
Run Code Online (Sandbox Code Playgroud)
更进一步,请考虑以下代码:
int i;
if (i is int) .... //Compiler warning: The given expression is always
//of the provided ('int') type.
Run Code Online (Sandbox Code Playgroud)
但是,var如果你这样做:
if (i is int j) ...
else ...
Run Code Online (Sandbox Code Playgroud)
您将不会得到任何警告(true在else子句中检测到表达式始终或无法访问的代码)基本上是相同的行为.
这让我想一想,如果我的初步推理可能是错误的.是否有一些模糊的使用/角落情况我错过了哪里真的有所作为?如果没有,那么缺少的警告和不一致的行为是编译器中的疏忽(甚至是错误)吗?
我正在审查一些原始类型的实现,特别是System.Double在.NET的Reference Source中,我偶然发现了这个:
[System.Runtime.Versioning.NonVersionable]
public static bool operator ==(Double left, Double right) {
return left == right;
}
[System.Runtime.Versioning.NonVersionable]
public static bool operator !=(Double left, Double right) {
return left != right;
}
Run Code Online (Sandbox Code Playgroud)
我知道这种自我参照运营商的实现可以反编译问题,因为解释在这里,但我的印象是,在参考源中的代码是实际的源代码和反编译的不输出下.
谁能解释一下这里真的发生了什么?
好的,请考虑以下代码:
const bool trueOrFalse = false;
const object constObject = null;
void Foo()
{
if (trueOrFalse)
{
int hash = constObject.GetHashCode();
}
if (constObject != null)
{
int hash = constObject.GetHashCode();
}
}
Run Code Online (Sandbox Code Playgroud)
trueOrFalse是一个编译时常量,因此,编译器正确警告int hash = o.GetHashCode();无法访问.
此外,constObject是一个编译时常量,因此编译器再次正确警告,这int hash = o.GetHashCode();是o != null永远不可达的true.
那么为什么编译器没有弄清楚:
if (true)
{
int hash = constObject.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)
是100%肯定是运行时异常,因此发出编译时错误?我知道这可能是一个愚蠢的角落案例,但编译器似乎非常聪明地推理编译时间常量值类型,因此,我期望它也可以找出这个带有引用类型的小角落情况.