2

メソッドに配列を渡そうとしています。配列には、ヌルにする必要があるオブジェクトが含まれています。このメソッドは、ループ内の各オブジェクトを単純に null にします。呼び出し元に反映するには、これが必要です。

サンプル コード (コードの良さとマイナーな構文上の問題は無視できます):

public class ABC
{
  ...
}

private void SomeMethod()
{
  var toBeNulledObj1 = new ABC();
  var toBeNulledObj2 = new ABC();
  var arrayOfNullableObjects = new ABC[]{toBeNulledObj1 ,toBeNulledObj2};
  NullingFunction(arrayOfNullableObjects);
}

private void NullingFunction(ABC[] arrayOfNullableObjects)
{
   for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
     {
        arrayOfNullableObjects[i] = null;
     }
}

明らかに、toBeNulledObj1&toBeNulledObj2は null ではありませんが、以前の値を保持していますが、arrayOfNullableObjects現在は 2 つのnullオブジェクトがあります。ref & out は collection パラメーターにのみ適用されることに気付きました (ここでarrayOfNullableObjectsは、ref も必要ありません)。コレクションの代わりにそれらを渡そうとしましたparamsが、それも役に立ちません (ref と params を組み合わせることはできません)。

質問:メソッド内のオブジェクトのコレクション内の各オブジェクトまたは任意のオブジェクトを変更して、変更が呼び出し元に表示されるようにするにはどうすればよいですか? コレクション自体を変更しているわけではありません。コンテンツ/メンバーを変更しているのではなく、参照自体を変更していないことに注意してくださいtoBeNulledObj1(nullまたは新しいオブジェクトへ)。

4

4 に答える 4

2

解決策 #1: 安全でないコード

1 つの解決策は、安全でないコードを使用することです。使用する前によく考える必要があります。私の回答に満足していただけるかどうかはわかりませんが、ここにあります。

static private void SomeMethod()
{
    ABC toBeNulledObj1 = new ABC();
    ABC toBeNulledObj2 = new ABC();

    IntPtr[] arrayOfNullableObjects = new IntPtr[] { MakeReference(ref toBeNulledObj1), MakeReference(ref toBeNulledObj2) };
    NullingFunction(arrayOfNullableObjects);
}

static private void NullingFunction(IntPtr[] arrayOfNullableObjects)
{
    foreach (IntPtr reference in arrayOfNullableObjects)
        ClearReference(reference);
}

/// <summary>
/// Makes the reference to the reference value of a reference type.
/// </summary>
static unsafe private IntPtr MakeReference<T>(ref T value)
    where T: class
{
    TypedReference reference = __makeref(value);
    return *(IntPtr*)&reference;
}

/// <summary>
/// Clears the reference to a reference type, using a reference to that reference value.
/// </summary>
static unsafe private void ClearReference(IntPtr reference)
{
    if (sizeof(IntPtr) == 4)
        *((int*)reference) = 0;
    else
        *((long*)reference) = 0;
}

解決策 #2: 匿名クラス

2 番目の解決策は、データを保持する匿名クラスを使用して行うことができます。この匿名クラス内のフィールドはクリアされます。欠点は、2 番目のクラスがあり、このクラスへの参照もクリアする必要があることです。(これは、に追加refoNullingFunctionセットoに追加することで実行nullできます。)もちろん、事前定義されたクラスを使用することもできますが、彼のソリューションは OP のコードに最も近いものです。

public static void SomeMethod()
{
    var container = new
    {
        toBeNulledObj1 = new ABC(),
        toBeNulledObj2 = new ABC(),
    };

    NullingFunction(container);
}

private static void NullingFunction<T>(T container)
    where T : class
{
    if (container == null)
        return;
    foreach(FieldInfo f in container.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
        if (f.FieldType.IsClass)
            f.SetValue(container, null);
}
于 2013-05-23T06:52:36.620 に答える
0

関数 A が変数への参照を保持している場合、つまり:

  var toBeNulledObj1 = new ABC();
  var toBeNulledObj2 = new ABC();

そして、これを関数 B に渡しません:

private NullingFunction(ABC[] arrayOfNullableObjects)

次に、関数 B が toBeNulledObj1 / 2 が指す参照を変更するためにできることは何もありません。

ref は params と一緒に許可されていないため (前述のとおり):

 private void NullingFunction(ref params ABC[] arrayOfNullableObjects)
    {
        for (int i = 0; i < arrayOfNullableObjects.Length; i++)
        {
            arrayOfNullableObjects[i] = null;
        }
    }

利用可能な代替手段は、オーバーロードを作成することです。

private void SomeMethod()
{
    var toBeNulledObj1 = new ABC();
    var toBeNulledObj2 = new ABC();
    NullingFunction(ref toBeNulledObj1, ref toBeNulledObj2);
    Console.ReadKey();
}

private void NullingFunction(ref ABC one)
{
    one = null;
}

private void NullingFunction(ref ABC one, ref ABC two)
{
    one = null;
    two = null;
}
于 2013-05-23T05:49:03.020 に答える
0

ラッピングは可能ですか?

class Wrapped<T> where T : new() {
   private T val = new T();
   ...
   public void Nullify() { val = null; }
}

private void SomeMethod()
{
  var toBeNulledObj1 = new Wrapped<ABC>();
  var toBeNulledObj2 = new Wrapped<ABC>();
  var arrayOfNullableObjects = new Wrapped<ABC>[]{toBeNulledObj1 ,toBeNulledObj2};
  NullingFunction(arrayOfNullableObjects);

  Debug.Assert(toBeNulledObj1.Get() == null);
  // Or...
  Debug.Assert(toBeNulledObj1.IsDefined == false);
  // Or...
  Debug.Assert(toBeNulledObj1.IsNull == true);
}

private void NullingFunction(Wrapped<ABC>[] arrayOfNullableObjects)
{
   for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
     {
        arrayOfNullableObjects[i].Nullify();
     }
}

(免責事項: 手作業でコンパイルされたコード :) エラーが含まれている可能性があります)

一般的なパターンとして必要な場合は、定数を使用して NullingFunction をパラメトリック (T, U) にすることができます。where U: Wrapped<T>

アイデアはNullable、C++ に精通している場合は、ref 型に似たもの、またはスマート ポインターのように見えるものを作成することです。

したがって、ラッパーは、値やプロパティなどT Get()を取得する (または T への暗黙的な変換) を持つことができます。IsDefined

于 2013-05-24T06:54:05.273 に答える