0

最近、私は自分自身が参照によって物事を渡す習慣にますます入り込んでいることに気づきました。オブジェクトに影響を与える可能性のあるものを追跡するのは難しいため、refを渡すことは「通常」悪い考えであると常に教えられてきたので、質問を投稿したいと思います。 '

私が最近参照を渡している例は、ビューステート内のレイジーインスタンス化されたオブジェクトです。コードビハインド内に、ヘルパーメソッドを利用するパブリックプロパティを持つプライベートフィールドがあります。現在の実装は次のとおりです。

ASPXコードビハインド

/// <summary>
/// Private field member for MyObject
/// </summary>
private Foobar _myObject = null;

/// <summary>
/// Gets or sets the current object
/// </summary>
public Foobar MyObject
{
    get
    {
        return this.ViewState.GetValue("MyObject", new Foobar(), ref this._myObject);
    }
    set
    {
        this.ViewState.SetValue("MyObject", value, ref this._myObject);
    }
}

これは、クラス内のフィールドおよびレイジーインスタンス化されたオブジェクトに対する多くの反復的なif割り当てチェックを置き換えることを目的としています。たとえば、ヘルパークラスがないと、次のようになります。

/// <summary>
/// Private field member for MyObject
/// </summary>
private Foobar _myObject = null;

/// <summary>
/// Gets or sets the current object
/// </summary>
public Foobar MyObject
{
    get
    {
        if (this._myObject != null)
        {
            return this._myObject;
        }

        var viewStateValue = this.ViewState["MyObject"];
        if (viewStateValue == null || !(viewStateValue is Foobar))
        {
            this.ViewState["MyObject"] = new Foobar();
        }

        return this._myObject = (Foobar)this.ViewState["MyObject"];
    }
    set
    {
        this._myObject = value;
        this.ViewState["MyObject"] = value;
    }
}

コードの両方のスニペットは同じことを達成しています。最初のアプローチはすべてを一元化することです。これは良いことですが、参照によって渡されます。この場合、これが良いアイデアかどうかはわかりません。

アドバイスや経験は大歓迎です。

を編集GetValueSetValue、ViewStateの拡張メソッドです 。コードは以下に提供されています。

/// <summary>
/// Gets a value from the current view state, if the type is correct and present
/// </summary>
public static T GetValue<T>(this StateBag source, string key, T @default)
{
    // check if the view state object exists, and is of the correct type
    object value = source[key];
    if (value == null || !(value is T))
    {
        return @default;
    }

    // return the object from the view state
    return (T)source[key];
}

/// <summary>
/// Sets the key value within the view state
/// </summary>
public static void SetValue<T>(this StateBag source, string key, T value)
{
    source[key] = value;
}

/// <summary>
/// Gets a value from the reference field helper, or the current view state, if the type is correct and present
/// </summary>
/// <returns>Returns a strongly typed session object, or default value</returns>
public static T GetValue<T>(this StateBag source, string key, T @default, ref T fieldHelper)
{
    return fieldHelper != null ? fieldHelper : fieldHelper = source.GetValue(key, @default);
}

/// <summary>
/// Sets the key value within the view state and the field helper
/// </summary>
/// <param name="value">The value</param>
public static void SetValue<T>(this StateBag source, string key, T value, ref T fieldHelper)
{
    source[key] = value;
    fieldHelper = value;
}
4

3 に答える 3

1

デイブのおかげでLazy<>クラスを試すことに抵抗できませんでした:-)。

public class Foobar
{
}

public class ViewState
{
  private readonly Lazy<Foobar> _foobar = new Lazy<Foobar>();

  public Foobar LazyFoobar
  {
    get { return _foobar.Value; }
  }
}

// Gets or creates the foobar
Foobar lazyFoobar = this.ViewState.LazyFoobar;

のクラスを実装すると、ViewState次の利点があります。

  1. 型安全です
  2. 遅延読み込みは簡単に統合できます
  3. キャッシュされたオブジェクトは必要ありません(より安定しています)
  4. コードは読み取り可能です
  5. コードは高速です(型変換なし)

元の質問に答えるには:参照を渡すと、他のコードでオブジェクトを置き換えることができます。呼び出された関数を信頼する必要があります。この関数はこの参照を他のオブジェクトに渡さず、後で元のオブジェクトを置き換えます。

于 2012-04-17T11:58:18.597 に答える
1

この場合に考慮すべきいくつかのオプション。

より少ないコード行と参照なしで同じ結果を達成できます。

get
{
    if (this._myObject == null)
        this._myObject = this.ViewState.GetValue<Foobar>("MyObject", new Foobar());
    return this._myObject;
}

ViewState.GetValueは、存在する場合はViewStateからオブジェクトを返すか、デフォルト(new FooBar())を設定して返します。これは、レイジープロパティの初期化を行うための非常に標準的な方法だと思います(または、.Net 4.0でレイジーを使用することもできます)。これを1行に要約することもできます。

return this._myObject = this._myObject ?? this.ViewState.GetValue("MyObject", new Foobar())

また、refを渡す代わりに、次のようなプライベートフィールドを設定するActionを渡すことができます。

this.ViewState.GetValue("MyObject", new Foobar(), newValue => this._myObject = newValue);

このように、ViewStateとFoobarはあまり結合されていないと思います。

また、デフォルト値の新しいFoorbar()を毎回作成する代わりに、()=> Foorbar()(またはLazy)を渡すことができるため、必要なときに1回だけ作成されます。

したがって、少なくともあなたの場合、refを使用する正当な理由はわかりません。

于 2012-04-17T10:03:19.533 に答える
-1

Referenceによる強制パスは、stringやintなどのプリミティブオブジェクトでのみ重要です。

refを使用しない場合は、関数で値を渡すだけで、メモリ内の別のオブジェクトを指します。

「ref」を使用するかどうかにかかわらず、クラスのような複雑なオブジェクトは常に参照によって渡されます...それはまったく違いはありません;-)

于 2012-04-17T09:54:06.413 に答える