2009-07-27 4 views
0

LINQとLambdaクエリーの結果について質問があります。たとえば、次のコードがあります。LINQとLambdaクエリーについての質問

class ClassA<T> { 
    public string Name { get; set; } 
    public T ObjectT { get; set; } 
} 

List<ClassA<T>> list; 
// list is populated 
// First way to get instance from list, reference type? 
ClassA<T> instance1 = list.Select(x=> x).Where(x=>x.Name == "A"). 
    FirstOrDefault(); 
// Second way to clone or copy instance from the list 
ClassA<T> instance2 = list.Select(x=> 
    new ClassA<T> { Name = x.Name, ObjectT = x.ObjectT}). 
    Where(x=> x.Name = "A").FirstOrDefault(); 

明らかに、instance2はlistにあるインスタンスのクローンまたはコピーです。インスタンス1はどうですか?これは新しいインスタンスか、リスト内のインスタンスへの参照ですか? instance1がリスト項目のオブジェクト参照である場合、そのプロパティの変更によってリスト内の同じオブジェクトが変更されることがあります。そうですか?

この場合、リスト内のオブジェクトに暗黙の影響を与えたくないので、2番目の戦略を使用する必要があります。しかし、検索されたインスタンスの変更にもリスト内で同じ変更が必要な場合は、戦略1を使用する必要があります。自分の理解が正しいかどうかはわかりません。コメントはありますか?

答えて

1

の線に沿って伸長法であろう。

  • ClassA<T>structを行います。あなたはあなたのリストのユーザーがリスト要素の周り混乱にできるようにしたいしなかった場合、私はこれらの選択肢を示唆している戦略について

    、。このようにして、クエリはリスト内の要素のコピーを返します。

  • ClassA<T>IClonableと同じように実装し、クローンしてから信頼できないコードに渡してください。

プロパティがクラスである可能性があることに注意してください。したがって、ClassA<T>オブジェクトをクローンした後でも、ObjectTプロパティは同じオブジェクトへの参照になり、すべてのユーザーコードでそのオブジェクトを変更できます。たぶん、ObjectTもクローンする必要があります。


class ClassA<T> : ICloneable 
{ 
    public string Name { get; set; } 
    public T ObjectT { get; set; } 

    public ClassA<T> Clone() 
    { 
     return (ClassA<T>)this.MemberwiseClone(); 
    } 

    object ICloneable.Clone() 
    { 
     return this.Clone(); 
    } 
} 

示唆したように、あなたはnull参照の問題を回避するために拡張メソッドを使用することができます。ご覧のとおり、この問題に対する解決策がいくつかあります。あなたはあなたの特定の問題に一層合ったものを選ぶべきです。

static class CloneableExt 
{ 
    public static T CloneNull<T>(this T obj) where T : class, ICloneable 
    { 
     if (obj == null) return null; 
     return (T)obj.Clone(); 
    } 
} 

EDIT 1:CloneableExtは何があなたの第二の例では行うことは、浅いコピーであることが、新しいインスタンスであるが、それでもrefenscedそのrefernceタイプのメンバーと

+0

私はこの方法が推奨されると思う、私はwaffledとnullを伝播する拡張メソッドに変更されました。 – Jimmy

+0

実際、拡張方法にはこの利点があります。実際には、任意の 'ICloneable'クラスを拡張することさえできます。 – jpbochi

1

はい、最初のクエリはリスト内のオブジェクトを複製しないため、instanceは実際のオブジェクトをlistから参照します。 2番目のクエリは、オブジェクトのクローンを明示的に構築します。

+0

が、浅いコピーを、右? ObjectTは元のインスタンスからの参照になります。 –

+0

はい、もちろんです。 –

2

これはリスト内のオブジェクトへの参照になります。あなたは何ができるか、選択は(X => x)が不要であることをコード

list.Where(x => x.Name == "A").FirstOrDefault().Clone() 

注意が生じ複製を返しクローン()関数を使用してコピーを作成することです。クローンinstance1list内側にある同じオブジェクトへの参照であり、classstructない)は、あなたClassA<T>ので

public static ClassA<T> Clone<T>(this ClassA<T> self) { 
    if (self == null) return null; 
    return new ClassA { 
     Name = self.Name, 
     ObjectT = self.ObjectT 
    } 
} 
+0

簡易版をありがとうございます。しかし、私にとっては読むのが本当に難しいです。 where節は、より明示的で読みやすいようにします。しかし、その後のコードがデフォルトでx => not-as-instanceとなった場合は、x戻り値の型を意味します。どちらに行くかわからない –

+0

ええ、FirstOrDefaultがそのオーバーロードをサポートしていないので、私はそれを元に戻しました。 – Jimmy

+0

それはちょうど浅いコピーを作成しませんか? ObjectTはまだ参考になるだけです.. –

0

を追加しました。

あなたはICloneableを実装する必要があり、それを正しく行うには:

class ClassA<T> : System.ICloneable where T : System.ICloneable 
    { 
     public string Name { get; set; } 
     public T ObjT { get; set; } 


     public object Clone() 
     { 
      var clone = new ClassA<T>(); 
      clone.Name = (string)Name.Clone(); 
      clone.ObjT = (T)ObjT.Clone(); 
      return clone; 
     } 
    } 

、その後

ClassA<T> instance2 = list.Where(x=> x.Name == "A").First().Clone();