Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.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#_Virtual_Abstract_Sealed_Optimization - Fatal编程技术网

C# 编译器如何优化由密封类实现的虚拟方法

C# 编译器如何优化由密封类实现的虚拟方法,c#,virtual,abstract,sealed,optimization,C#,Virtual,Abstract,Sealed,Optimization,我想知道下面的代码是如何优化的。特别是关于虚拟和直接呼叫。我已经评论过我认为一切都是如何优化的,但这些只是猜测 public abstract class Super { public abstract void Foo(); public void FooUser() { Foo(); } } public class Child1 : Super { public override void Foo() {

我想知道下面的代码是如何优化的。特别是关于虚拟和直接呼叫。我已经评论过我认为一切都是如何优化的,但这些只是猜测

public abstract class Super
{
    public abstract void Foo();

    public void FooUser()
    {
        Foo();
    }
}

public class Child1 : Super
{
    public override void Foo()
    {
        //doSomething
    }
}

public class SealedChild : Super
{
    public override void Foo()
    {
        //doSomething
    }
}

class Program
{
    void main()
    {
        Child1 child1 = new Child1();
        child1.Foo(); //Virtual call?
        child1.FooUser(); //Direct call and then a virtual call. 

        SealedChild sealedChild = new SealedChild();
        sealedChild.Foo(); //Direct call?
        sealedChild.FooUser(); 
        /* Two options: either a direct call & then a virtual call
         * Or: direct call with a parameter that has a function pointer to Foo, and then a direct call to foo.
         */

        Super super = child1;
        super.Foo(); //Virtual call.
        super.FooUser(); //Virtual call then direct call.
    }
}

编译器根本不做任何类型的优化。它总是生成一条IL“callvirt”指令(call virtual)。理论上,运行时可以删除调用的虚拟部分,但我看到和尝试过的每个基准都表明情况并非如此。考虑到即使是完全静态的C++编译器也不能在微不足道的情况下这样做,JIT似乎不太可能把它关闭。而且,即使他们能让它发挥作用,他们也可以把时间花在一系列更常见的性能缺陷上


哦,这解释了为什么C总是生成callvirt。

编译器根本不进行任何类型的优化。它总是生成一条IL“callvirt”指令(call virtual)。理论上,运行时可以删除调用的虚拟部分,但我看到和尝试过的每个基准都表明情况并非如此。考虑到即使是完全静态的C++编译器也不能在微不足道的情况下这样做,JIT似乎不太可能把它关闭。而且,即使他们能让它发挥作用,他们也可以把时间花在一系列更常见的性能缺陷上


哦,这解释了为什么C#总是生成callvirt。

如果它被密封(可能编辑它?),编译器或JIT可以在已知对象是密封子对象时发出非虚拟调用,从而保存间接寻址。Java做到了这一点,而C#似乎没有做到这一点;但是我不知道JIT会做什么。

如果它被密封(可能编辑它?),编译器或JIT可以在已知对象是密封子对象时发出非虚拟调用,从而保存间接寻址。Java做到了这一点,而C#似乎没有做到这一点;但是我不知道JIT会做什么。

在密封类上有一个虚拟方法,并且对象引用的类型是密封类的情况下,可以避免虚拟调用。以下面的例子为例。没有实际的理由需要虚拟地调用GetName,因为我们知道不可能有父类的子类,因此没有进一步的虚拟分派

sealed class Parent : Child  {
  public override string GetName() { return "foo"; }
}

public void Test() {
  var p = new Parent();
  var name = p.GetName();
}
编译器可以选择注意到这一点,并输出call IL指令而不是callvirt。然而,C#和VB.Net编译器都选择不执行此优化。两者都将发出callvirt

JIT也可以自由地进行这样的优化。它也选择不这样做

然而,这并不意味着你不应该封闭你的课程。类应该被密封,除非你真的想让某人继承它们。否则,您将面临无法准确估算成本的情况


此外,没有什么可以阻止编译器和JIT在以后实现它

在密封类上有一个虚拟方法,并且对象引用的类型是密封类的情况下,可以避免虚拟调用。以下面的例子为例。没有实际的理由需要虚拟地调用GetName,因为我们知道不可能有父类的子类,因此没有进一步的虚拟分派

sealed class Parent : Child  {
  public override string GetName() { return "foo"; }
}

public void Test() {
  var p = new Parent();
  var name = p.GetName();
}
编译器可以选择注意到这一点,并输出call IL指令而不是callvirt。然而,C#和VB.Net编译器都选择不执行此优化。两者都将发出callvirt

JIT也可以自由地进行这样的优化。它也选择不这样做

然而,这并不意味着你不应该封闭你的课程。类应该被密封,除非你真的想让某人继承它们。否则,您将面临无法准确估算成本的情况


此外,没有什么可以阻止编译器和JIT在以后实现它

您的“SealedClass”实际上并没有定义为sealed。因此,它与您的Child1类没有什么不同。您的“sealed类”实际上并没有定义为sealed。因此,它与您的Child1类没有什么不同。只是一个更新。
没有任何东西阻止编译器和JIT在以后实现此功能。
发生在Core2.0或FW 4.7.1之后的RyuJIT中。看见很高兴你提到它可以改变。只是一个更新。
没有任何东西阻止编译器和JIT在以后实现此功能。
发生在Core2.0或FW 4.7.1之后的RyuJIT中。看见很高兴你提到它可以改变。