Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么是';是';实施为';作为';?_C#_.net_As Keyword - Fatal编程技术网

C# 为什么是';是';实施为';作为';?

C# 为什么是';是';实施为';作为';?,c#,.net,as-keyword,C#,.net,As Keyword,考虑到这是一个非常自然的用例(如果您不知道实际上做了什么) 有效等效(即,由上述代码生成的编译器将等效)为: 编辑: 我想我没有把问题说清楚。我永远不会写第二个片段,因为它当然是多余的。我声称编译器在编译第一个代码段时生成的CIL与第二个代码段等效,这是多余的。问题:a)这是正确的吗?b) 如果是这样,为什么是这样实现的 这是因为我发现第一个片段比真正写得好的片段更清晰、更漂亮 Bar y = x as Bar; if (y != null) { something(); } 结论: 优

考虑到这是一个非常自然的用例(如果您不知道
实际上做了什么)

有效等效(即,由上述代码生成的编译器将等效)为:

编辑:

我想我没有把问题说清楚。我永远不会写第二个片段,因为它当然是多余的。我声称编译器在编译第一个代码段时生成的CIL与第二个代码段等效,这是多余的。问题:a)这是正确的吗?b) 如果是这样,为什么
是这样实现的

这是因为我发现第一个片段比真正写得好的片段更清晰、更漂亮

Bar y = x as Bar;
if (y != null) {
   something();
}
结论:

优化
/
作为
案例不是编译器的责任,而是JIT的责任

此外,与空检查一样,它的指令数比这两种可选方法都少(且成本更低)(
is
as
is
cast

增编:

带nullcheck的as的CIL(.NET 3.5):

is和cast的CIL(.NET 3.5):

is和as的CIL(.NET 3.5):


这些都是为了简短而编辑的(方法声明、NOP和对something()的调用已被删除)。

您不会再做第二次
y=x作为条形图
,因为您已经有了y,它是Bar。

在您的示例中,使用
作为
是多余的。由于您已经知道
x是条形的
,因此应该使用强制转换:

if (x is Bar)
{
    Bay y = (Bar)x;
}
或者,使用
转换为
,只需检查null:

Bar y = x as Bar;
if (y != null)
{

}

首先,我不同意你的假设,即这是更典型的用例。这可能是您最喜欢的方法,但惯用的方法是“as+null-check”样式:

正如您所发现的,“is”方法需要额外的“As”或cast,这就是为什么在我的经验中,带有null检查的“As”是实现这一点的标准方法

我不认为这种“as”方法有什么冒犯性,就我个人而言,我不认为它比任何其他代码更令人不快


至于你的实际问题,为什么
关键字是按照
As
关键字来实现的,我不知道,但我确实喜欢你问题中的文字游戏:)我怀疑两者都不是按照另一个来实现的,而是工具(我想是反射器)您曾经从IL生成C#,将IL解释为

那么,可用的IL指令(isinst)将返回适当类型的对象,如果无法进行这种转换,则返回null。如果转换不可能,它不会抛出异常

有鉴于此,“is”和“as”都是很容易实现的。在本例中,我不会声称“is”被实现为“as”,只是底层的IL指令允许两者同时发生。现在,为什么编译器不能将后跟“as”的“is”优化为单个isinst调用,那是另一回事了。在本例中,它可能与变量作用域有关(即使在这是IL时,作用域实际上并不存在)

编辑

再想一想,如果不知道所讨论的变量不会从其他线程更新,就无法将“is”后跟“as”优化为单个isinst调用

假设x是一个字符串:

//Thread1
if(x is string)

//Thread2
x = new ComplexObject();

//Thread1
    y = x as string

这里,y应该为空。

我强烈怀疑isas快,并且不需要分配。因此,如果x很少是Bar,那么第一个片段就很好了。如果x大部分为条形,则建议使用as,因为不需要第二次浇铸。这取决于代码的用法和环境。

根据Eric Lippert的博客文章,这是一个编译器过程。引述:

然后我们运行一个优化过程 重写琐碎的“是”和“是” 接线员


因此,也许这就是为什么您看到为两个代码段生成相同的CIL的原因。

您现在可以将代码编写为

DoIfOfType<Bar>(possibleBar, b => b.something())
DoIfOfType(可能的b栏,b=>b.something())

我想说的是,这更清楚了一点,但如果没有编译器的真正魔力,速度就不会那么快。

如果将声明放在循环中,“y”的范围会缩小


写这篇文章的人可能更喜欢将“x”转换为“T”而不是“(T)x”,并且想要限制“y”的范围。

您忘记了值类型。例如:

    static void Main(string[] args)
    {
        ValueType vt;
        FooClass f = vt as FooClass;

    }

    private class FooClass
    {
        public int Bar { get; set; }
    }
不会编译,因为值类型不能像这样转换

a) 这是正确的吗

是的,不过我会用另一种方式说。您是说“is”是as的一个语法糖,后跟null检查。我会用另一种方式说:“as”是“检查类型实现,如果成功则强制转换,如果失败则为null”的语法糖

也就是说,我更倾向于说

if (x is Bar) { 
   Bar y = x as Bar; 
   something(); 
} 
实际上相当于

if (x is Bar) { 
   Bar y = (x is Bar) ? (Bar)x : (Bar) null; 
   something(); 
} 
看,你想用“是”来定义“是”,而不是反过来。问题真的应该是“为什么要如此实施?”:-)

b) 如果是,为什么要这样实施

因为这是规范的正确实现


我想我没有遵循你的思路。这种实现有什么问题吗?您希望它如何实施?您可以使用“isinst”和“castclass”说明;请描述您希望看到的程序的codegen。

我不会,但如果我以更自然(is)的方式编写,编译器不会将其称为典型用例,更典型的是Bar y=x as Bar;如果(y!=null){do_stuff();}。如果你使用as,为什么要先检查is?第一个对我来说就像是一个不知道as做了什么的人写的。是的,但那是因为你知道as做了什么:)。如果你忘记了你所知道的,第一个不是看起来更漂亮吗?因为我刚刚更新了我的答案
Bar y = x as Bar; 
if (y != null) { 
   something(); 
}
//Thread1
if(x is string)

//Thread2
x = new ComplexObject();

//Thread1
    y = x as string
DoIfOfType<Bar>(possibleBar, b => b.something())
    static void Main(string[] args)
    {
        ValueType vt;
        FooClass f = vt as FooClass;

    }

    private class FooClass
    {
        public int Bar { get; set; }
    }
if (x is Bar) { 
   Bar y = x as Bar; 
   something(); 
} 
if (x is Bar) { 
   Bar y = (x is Bar) ? (Bar)x : (Bar) null; 
   something(); 
}