C# - 在一个初始化内部类字段倒闭? [英] C# - closures over class fields inside an initializer?

查看:84
本文介绍了C# - 在一个初始化内部类字段倒闭?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的代码:

using System;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            var square = new Square(4);
            Console.WriteLine(square.Calculate());
        }
    }

    class MathOp
    {        
        protected MathOp(Func<int> calc) { _calc = calc; }
        public int Calculate() { return _calc(); }
        private Func<int> _calc;
    }

    class Square : MathOp
    {
        public Square(int operand)
            : base(() => _operand * _operand)  // runtime exception
        {
            _operand = operand;
        }

        private int _operand;
    }
}



(忽略一流的设计,我不实际!写一个计算器的代码只是表示该花一段时间来缩小一个更大的问题最小摄制)

(ignore the class design; I'm not actually writing a calculator! this code merely represents a minimal repro for a much bigger problem that took awhile to narrow down)

我希望它可以:


  • 打印16或

  • 如果关闭了一个成员字段中,这是不允许抛出一个编译时错误方案

相反,我得到的指示线抛出荒谬的异常。在3.0 CLR这是一个的的NullReferenceException 的;关于Silverlight的CLR是臭名昭著的操作可能会破坏运行。

Instead I get a nonsensical exception thrown at the indicated line. On the 3.0 CLR it's a NullReferenceException; on the Silverlight CLR it's the infamous Operation could destabilize the runtime.

推荐答案

这不会导致在编译时错误,因为它的的一个有效的封闭。

It's not going to result in a compile-time error because it is a valid closure.

问题是,这个不是在创建关闭时尚未初始化。您的构造函数时提供这样的说法没有实际尚未运行。所以造成的NullReferenceException 还算是符合逻辑的。这是这个这是

The problem is that this is not initialized yet at the time the closure is created. Your constructor hasn't actually run yet when that argument is supplied. So the resulting NullReferenceException is actually quite logical. It's this that's null!

我会证明它给你。让我们重写代码是这样的:

I'll prove it to you. Let's rewrite the code this way:

class Program
{
    static void Main(string[] args)
    {
        var test = new DerivedTest();
        object o = test.Func();
        Console.WriteLine(o == null);
        Console.ReadLine();
    }
}

class BaseTest
{
    public BaseTest(Func<object> func)
    {
        this.Func = func;
    }

    public Func<object> Func { get; private set; }
}

class DerivedTest : BaseTest
{
    public DerivedTest() : base(() => this)
    {
    }
}

猜猜这是什么打印?是的,这是真正,关闭返回,因为这个在执行时未初始化。

Guess what this prints? Yep, it's true, the closure returns null because this is not initialized when it executes.

修改

我很好奇托马斯声明中,想,也许他们会在随后发布VS改变的行为。其实,我发现了一个的 Microsoft连接问题了解这事。被关闭的不会解决。奇怪的。

I was curious about Thomas's statement, thinking that maybe they'd changed the behaviour in a subsequent VS release. I actually found a Microsoft Connect issue about this very thing. It was closed as "won't fix." Odd.

由于微软在他们的回应说,这通常是无效的,从参数中使用这个参考基本构造函数调用列表;参考根本没有在那个时间点存在,如果您尝试使用它,你会真正得到一个编译时错误一丝不挂。所以,可以说是它的的生产用于封闭的情况下编译错误,但这个引用从编译器,(至少在VS隐藏2008)必须知道的的它瓶盖内,以阻止人们这样做。这不,这就是为什么你最终有这种行为。

As Microsoft says in their response, it is normally invalid to use the this reference from within the argument list of a base constructor call; the reference simply does not exist at that point in time and you will actually get a compile-time error if you try to use it "naked." So, arguably it should produce a compile error for the closure case, but the this reference is hidden from the compiler, which (at least in VS 2008) would have to know to look for it inside the closure in order to prevent people from doing this. It doesn't, which is why you end up with this behaviour.

这篇关于C# - 在一个初始化内部类字段倒闭?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆