5

決して実行されないが、コンパイル出力の一部である必要があるコードが必要な、かなり難解なケースがあります。私は独自のものを考え出すことができましたが、コミュニティに尋ねています: 常に false と評価され、コンパイラの警告を生成せず、最終的なビルド出力で囲まれたコード ブロックを保持する、最も単純で最速の C# 式は何ですか?

更新:質問の背後にある理論的根拠の説明が要求されたため、Monotouch リンカは静的コード分析を実行して、参照されていないすべてのシンボルを最終ビルドから取り除き、生成されたバイナリのサイズを小さくします。これは、リフレクションを介してのみアクセスされるプロパティに問題を引き起こします。

4

7 に答える 7

6

私はシンプルに行きます...

public static bool False() {
    return false;
}
public static void Foo() {
    if (False()) {
       ...
    }
}

JIT も納得させる必要がある場合 (インライン化)、追加[MethodImpl(MethodImplOptions.NoInlining)]します。False()

于 2013-05-13T08:02:49.790 に答える
5

【2回目の編集】

@Guillaume は、OP へのコメントで正しい答えを提案しているように思えます。そこで彼は、OP がカスタム リンクを使用して、問題のプロパティが最適化されないようにすることを提案しています: http://docs.xamarin.com /guides/ios/advanced_topics/linker#3.custom-linking

@Guillaumeがそれを答えとして書いた場合、彼が正当に信用できるように、この編集を削除します.


元の答え:

どうですか:

if ("".Length > 0)

リリースビルド(VS2012、.Net 4.5)のリフレクターでこのコードをチェックしました

void Run()
{
    if ("".Length > 0)
    {
        Console.WriteLine();
    }
}

そして、次の IL が生成されます。

.method private hidebysig instance void Run() cil managed
{
    .maxstack 8
    L_0000: ldstr ""
    L_0005: callvirt instance int32 [mscorlib]System.String::get_Length()
    L_000a: ldc.i4.0 
    L_000b: ble L_0015
    L_0010: call void [mscorlib]System.Console::WriteLine()
    L_0015: ret 
}

編集: これが機能するかどうかについてはいくつかの議論があるように思われるので、もう少し証拠を提供させてください.

目標は、生成されたコードがプロパティにアクセスできるようにすることです。

この C# コードを考えると:

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            new Program().Run();
        }

        void Run()
        {
            if ("".Length > 0)
            {
                Test t = new Test();
                Trace.WriteLine(t.Property); // Make sure we use the property.
            }
        }
    }

    internal class Test
    {
        public int Property { get; set; }
    }
}

Run()リリース ビルドのメソッド用に生成された IL コードは次のとおりです。

.method private hidebysig instance void Run() cil managed
{
    .maxstack 5
    .locals init (
        [0] class ConsoleApplication1.Test t)
    L_0000: ldstr ""
    L_0005: callvirt instance int32 [mscorlib]System.String::get_Length()
    L_000a: ldc.i4.0 
    L_000b: ble L_0026
    L_0010: newobj instance void ConsoleApplication1.Test::.ctor()
    L_0015: stloc.0 
    L_0016: ldloc.0 
    L_0017: callvirt instance int32 ConsoleApplication1.Test::get_Property()
    L_001c: box int32
    L_0021: call void [System]System.Diagnostics.Trace::WriteLine(object)
    L_0026: ret 
}

したがって、プロパティは出力コードで確実に参照されています。したがって、これは要件を満たしています。

于 2013-05-13T07:50:32.983 に答える
2

null ではないことがわかっている場合は、オブジェクト参照 == null をテストするのが最速だと思います。

更新します。他の回答のいくつかを見て、私の推測では、スタンドアローンで明らかに間違っているものは、あなたの論理から知っているものと比較して、最適化されて取り除かれるリスクが高いと思います (今日でなくても、おそらく将来的に)。プログラムは偽でなければなりません。低レベルのオペコードに関して言えば、何か != 0 をテストすることは、私が知っている最速の操作の 1 つです。

于 2013-05-13T07:49:52.400 に答える
1

私はここで創造的になろうとしているだけです (以前に提案されたことを何も提案していません)、おそらく:

if (new object().GetType() == typeof(string))

それが最適化されるとは思いませんが、それをテストできる場所にはありません。

于 2013-05-13T08:02:40.587 に答える
0
if(false)
{
}

...私の推測です:)

于 2013-05-13T07:50:16.170 に答える
0
//Try using `if(1 == 2) {...}`, is that what you want? 

編集:以下はコンパイラによって検出されるべきではないと思います:

if(this.GetType().ToString().Equals(string.Empty)
{
    ......
}
于 2013-05-13T07:50:18.803 に答える