7

遅延評価されるプロパティを記述していることに気付くことがよくあります。何かのようなもの:

if (backingField == null) 
  backingField = SomeOperation();
return backingField;

これは多くのコードではありませんが、多くのプロパティがある場合は何度も繰り返されます。

LazyProperty というクラスを定義することを考えています。

public class LazyProperty<T>
    {
    private readonly Func<T> getter;

    public LazyProperty(Func<T> getter)
    {
        this.getter = getter;
    }

    private bool loaded = false;
    private T propertyValue;

    public T Value
    {
        get
        {
            if (!loaded)
            {
                propertyValue = getter();
                loaded = true;
            }
            return propertyValue;
        }
    }

    public static implicit operator T(LazyProperty<T> rhs)
    {
        return rhs.Value;
    }
}

これにより、次のようなフィールドを初期化できます。

first = new LazyProperty<HeavyObject>(() => new HeavyObject { MyProperty = Value });

そして、プロパティの本体は次のように縮小できます。

public HeavyObject First { get { return first; } }

これは、当社のほとんどの製品で共有される共通のクラス ライブラリに含まれるため、会社のほとんどで使用されます。

これが良いアイデアかどうかは、私には判断できません。ソリューションには、次のようないくつかの長所があると思います。

  • 少ないコード
  • きれいなコード

欠点としては、特に開発者が LazyProperty クラスに慣れていない場合、コードを見て何が起こるかを正確に判断するのが難しくなります。

どう思いますか ?これは良い考えですか、それともやめるべきですか? また、暗黙の演算子は良い考えですか、それとも、このクラスを使用する必要がある場合は、Value プロパティを明示的に使用することをお勧めしますか?

意見や提案を歓迎します:-)

4

10 に答える 10

7

過度に衒学的になるために:

コードの繰り返しを避けるための提案されたソリューション:

private LazyProperty<HeavyObject> first = 
  new LazyProperty<HeavyObject>(() => new HeavyObject { MyProperty = Value });
public HeavyObject First { 
  get { 
    return first; 
  } 
}

実際には、繰り返したくないコードよりも多くの文字があります:

private HeavyObject first;
public HeavyObject First { 
  get {
    if (first == null) first = new HeavyObject { MyProperty = Value };
    return first;
  }
}

それとは別に、暗黙のキャストにより、コードが非常に理解しにくくなったと思います。単純に最初に返されるメソッドが、実際には HeavyObject を作成することになるとは思いもしませんでした。少なくとも、暗黙的な変換を削除して、プロパティから first.Value を返したはずです。

于 2009-01-13T19:24:56.363 に答える
5

絶対にしないでください。

一般に、この種の遅延初期化プロパティを使用することは、あるケースでは有効な設計上の選択です:SomeOperation();高価な操作 (DB ヒットが必要な場合や計算上の I/O の観点から) であり、多くの場合、そうしないことが確実な場合アクセスする必要があります。

とはいえ、デフォルトでは熱心な初期化を行うべきであり、プロファイラーがそれがボトルネックであると判断した場合は、遅延初期化に変更します。

そのような抽象化を作成したいという衝動を感じたら、それは匂いです。

于 2009-01-13T19:27:28.293 に答える
4

確かに、少なくともLazyPropery<T>値型にする必要があります。そうしないと、システム内のすべての「遅延ロード」プロパティにメモリとGCプレッシャーが追加されます。

また、マルチスレッドのシナリオはどうですか?同時にプロパティを要求する2つのスレッドについて考えてみます。ロックしないと、基になるプロパティの2つのインスタンスを作成できる可能性があります。一般的なケースでロックを回避するには、ダブルチェックロックを実行する必要があります。

于 2009-01-13T19:07:17.867 に答える
2

私は最初のコードを好みます。なぜなら、a)それは私がすぐに理解できるプロパティを持つ非常に一般的なパターンであり、b)あなたが提起したポイント:どこでいつを理解するために見上げる必要がある隠された魔法がないからです値が取得されています。

于 2009-01-13T19:04:12.460 に答える
1

コードがはるかに少なく、エレガントであるという点で私はこのアイデアが好きですが、それを見て何が起こっているのかを理解するのが難しくなるという事実について非常に心配しています。私が考える唯一の方法は、「怠惰な」方法を使用して設定された変数の規則を設定し、それが使用されている場所にコメントを付けることです。今では、これらのルールを適用するコンパイラや何かは存在しないので、YMMVのままです。

結局のところ、私にとって、このような決定は、誰がそれを見るのか、そしてそれらのプログラマーの質に帰着します。仲間の開発者がそれを正しく使用し、うまくコメントすることを信頼できる場合は、それを選択してください。ただし、そうでない場合は、簡単に理解して従う方法で行う方がよいでしょう。/ my 2cents

于 2009-01-13T19:03:09.747 に答える
1

開発者が理解していないことを心配することは、このようなことをすることに反対する良い議論ではないと思います...

あなたがそれを考えるなら、あなたは誰かがあなたがしたことを理解しないのを恐れて何もすることができませんでした

中央リポジトリにチュートリアルなどを書くことができます。ここに、この種のメモのwikiがあります。

全体として、これは良い実装のアイデアだと思います(遅延読み込みが良いアイデアかどうかについては、議論を始めたくありません)。

于 2009-01-13T19:06:43.267 に答える
1

この場合、Visual Studio コード スニペットを作成します。それがあなたが本当にすべきことだと思います。

たとえば、ASP.NET コントロールを作成するとき、ViewState に多くのデータが格納されることがよくあるため、次のようなコード スニペットを作成しました。

public Type Value
{
    get
    {
        if(ViewState["key"] == null)
            ViewState["key"] = someDefaultValue;
        return (Type)ViewState["key"];
    }
    set{ ViewState["key"] = value; }
}

このように、少しの作業 (型、キー、名前、および既定値の定義) だけでコードを簡単に作成できます。再利用可能ですが、他の開発者が理解できないような複雑なコードの欠点はありません。

于 2009-01-13T19:22:42.563 に答える
0

私はあなたの解決策がとても賢いので好きですが、それを使ってもあなたはあまり勝てないと思います。パブリックプロパティにプライベートフィールドを遅延ロードすることは、間違いなくコードを複製できる場所です。ただし、これは、共通の場所にリファクタリングする必要があるコードではなく、使用するパターンとして常に私を驚かせてきました。

シリアル化を行う場合、将来、アプローチが問題になる可能性があります。また、カスタムタイプで何をしているのかを最初に理解するのは、より混乱します。

全体として、私はあなたの試みを称賛し、その巧妙さに感謝しますが、上記の理由で元の解決策に戻ることをお勧めします。

于 2009-01-13T19:06:48.430 に答える
0

個人的には、特に値型に使用することの欠点を考慮すると (Kent が述べたように)、LazyProperty クラスはそのままでは使用を正当化するのに十分な価値を提供するとは思いません。他の機能 (マルチスレッド化など) が必要な場合は、ThreadSafeLazyProperty クラスとして正当化される可能性があります。

暗黙のプロパティに関しては、「値」プロパティの方が好きです。もう少しタイピングが必要ですが、私にははるかに明確です。

于 2009-01-13T19:23:57.537 に答える
0

これは面白いアイデアだと思います。まず、呼び出し元のコードから Lazy プロパティを非表示にすることをお勧めします。それが遅延であることをドメイン モデルに漏らしたくありません。暗黙の演算子で何をしているのか、それを守ってください。

このアプローチを使用して、たとえばロックの詳細を処理および抽象化する方法が気に入っています。そうすれば価値やメリットがあると思います。ダブルロックパターンに注意してロックを追加すると、非常に簡単に間違えてしまいます。

于 2009-01-13T19:43:18.043 に答える