4

デバッガーをアタッチ (F5) して Visual Studio 内からアプリを起動すると、アプリは正常に動作していました。しかし、デバッガーを接続せずにアプリを起動したとき (Ctrl-F5 または .exe ファイルを起動)、StackOverflowException幸運にも Windows イベント ログに記録された.

問題のあるコードは次のとおりです。

namespace Caliburn.Micro.Contrib
{
    public static class FrameworkExtensions
    {
        public static class ViewLocator
        {
            static readonly Func<string,object, IEnumerable<string>> _baseTransformName = Micro.ViewLocator.TransformName;

            public static void EnableContextFallback()
            {
                Caliburn.Micro.ViewLocator.TransformName = FallbackNameTransform;
            }    

            static IEnumerable<string> FallbackNameTransform(string typeName, object context)
            {
                var names = _baseTransformName(typeName, context);
                if (context != null)
                {
                    names = names.Union(_baseTransformName(typeName, null));
                }

                return names;
            }
        }
    }
}

FrameworkExtensions.EnableContextFallack()アプリの起動中にメソッドを呼び出しましたが、最初の呼び出し中に StackOverflowException が発生しましたCaliburn.Micro.ViewLocator.TransformName。つまり、デバッガーがアタッチされていない場合は が呼び出された後、デバッガーがアタッチされている場合は が呼び出される前に_baseTransformName、変数が初期化されます。 EnableContextFallback() EnableContextFallback()

静的コンストラクターを追加することでバグを修正し、コンストラクターで変数を割り当てることができました

namespace Caliburn.Micro.Contrib
{
    public static class FrameworkExtensions
    {
        public static class ViewLocator
        {
            static readonly Func<string, object, IEnumerable<string>> _baseTransformName;

            static ViewLocator()
            {
                 _baseTransformName = Micro.ViewLocator.TransformName;
            }

            public static void EnableContextFallback()
            {
                Caliburn.Micro.ViewLocator.TransformName = FallbackNameTransform;
            }    

            static IEnumerable<string> FallbackNameTransform(string typeName, object context)
            {
                var names = _baseTransformName(typeName, context);
                if (context != null)
                {
                    names = names.Union(_baseTransformName(typeName, null));
                }

                return names;
            }
        }
    }
}

これにより、 の最初の呼び出しの前に変数_baseTransformNameが常に設定されますEnableContextFallback()

問題は、デバッガーがアタッチされているときに静的変数の初期化動作が異なるのはなぜですか?また、異なる動作を「無効にする」方法があるのですか?

乾杯

4

1 に答える 1

1

問題は、デバッガーがアタッチされているときに静的変数の初期化動作が異なるのはなぜですか?また、異なる動作を「無効にする」方法があるのですか?

静的コンストラクターがない場合、静的変数初期化子の動作についてはほとんど保証されません。実際、静的変数初期化子を呼び出さずにクラスのインスタンスを作成することもできます! デバッガーを使用している場合、CLR はあらゆる種類のことを別の方法で行います (特に JIT 周り)。

静的コンストラクターを使用することは、おそらく、より予測可能な初期化動作を提供する最良の方法です。

詳細については、.NET 4 での型初期化の変更に関する私のブログ投稿を参照してください。

于 2012-04-30T14:45:25.873 に答える