2012-06-24 11 views
20

プロパティ自体を関数に渡すメソッドを探しています。プロパティの値ではありません。関数は、どのプロパティがソートに使用されるかを事前に知っていません。この例の最も簡単な方法は、異なるパラメータタイプで4つの上書きを作成することです。他の方法は、機能内でtypeof()を使用しています。 Class1に何百ものプロパティがある場合、これらの方法はどちらも受け入れられません。これまでのところ私は、以下の方法を見つけました:C#でパラメータとして機能するプロパティ自体を渡す

class Class1 
{ 
    string vehName; 
    int maxSpeed; 
    int fuelCapacity; 
    bool isFlying; 
} 

class Processor 
{ 
    List<Class1> vehicles = null; 
    Processor(List<Class1> input) 
    { 
     vehicles = input; 
    } 

    List<Class1> sortBy(List<Class1> toSort, string propName) 
    { 
     if (toSort != null && toSort.Count > 0) 
     { 
      return toSort.OrderBy(x => typeof(Class1).GetProperty(propName).GetValue(x, null)).ToList(); 
     } 
     else return null; 
    } 
} 

class OuterUser 
{ 
    List<Class1> vehicles = new List<Class1>(); 
    // ... fill the list 
    Processor pr = new Processor(vehicles); 
    List<Class1> sorted = pr.sortBy("maxSpeed"); 
} 

処理関数に文字列を渡すとき、私はので、「ヒューマンエラー」のリスクが、この方法が好きではありません。文字列がコードの他の部分によって生成されるとき、これはさらに醜いでしょう。 Class1プロパティの引き渡しをさらに処理するために機能させるために、より洗練された方法を提案してください。使用方法の最良の選択肢は次のようなものです(0120)。

vehicles = sortBy(vehicles, Class1.maxSpeed); 
+2

.NETバージョン? – alf

+0

ソートに使用するプロパティは、最初にどのように選択されていますか? – arootbeer

+0

version .NET 4.0 –

答えて

39

メソッドにプロパティアクセサを渡すことができます。

List<Class1> SortBy(List<Class1> toSort, Func<Class1, IComparable> getProp) 
{ 
    if (toSort != null && toSort.Count > 0) { 
     return toSort 
      .OrderBy(x => getProp(x)) 
      .ToList(); 
    } 
    return null; 
} 

あなたはこのようにそれを呼び出します。

var result = SortBy(toSort, x => x.maxSpeed); 

しかし、あなたはさらに一歩進み、独自の拡張メソッドを書くことができます。

public static class CollectionExtensions 
{ 
    public static List<TSource> OrderByAsListOrNull<TSource, TKey>(
     this ICollection<TSource> collection, Func<TSource,TKey> keySelector) 

     if (collection != null && collection.Count > 0) { 
      return collection 
       .OrderBy(x => keySelector(x)) 
       .ToList(); 
     } 
     return null; 
    } 
} 

今、あなたは、2つの条件を満たさなければならないので、私はICollection<T>として最初のパラメータを宣言し、この

List<Class1> sorted = toSort.OrderByAsListOrNull(x => x.maxSpeed); 

Person[] people = ...; 
List<Person> sortedPeople = people.OrderByAsListOrNull(p => p.LastName); 

ノートのように並べ替えることができます。

  1. が必要ですプロパティ
  2. LINQメソッドOrderByを適用できるようにするには、IEnumerable<T>である必要があります。

List<Class1>は、ICollection<T>であるが、多くの他のコレクションと同様に配列Person[]である。

+0

このメソッドは、LINQのOrderByとは何も変わりませんか? –

+0

オリビエ、ありがとう!または、merci beaucoup :) –

+0

@Chris Gessler:ソースコレクションが 'null'または' Count'が '0'の場合は' null'が返されます。そうでない場合は 'List 'が返されます。ソースが 'null'ならばLINQの' OrderBy'は例外をスローし、それ以外の場合は 'IEnumerable 'を返します。この方法が他の人にとって本当に有用かどうかはわかりませんが、OPには明らかに必要です。 –

3

なぜこのようなLinqを使用しないのですか? Like:

vehicles.OrderBy(v => v.maxSpeed).ToList(); 
+0

他のクラスは 'Processor'を使用します。彼らは '車両'を見るべきではありません。さらに、 'sortBy'はより多くの論理を持ちます(昇順/降順/何らかのフィルタリング)... –

+0

私は、上記の@olivierからの答えを見て、自分の拡張メソッド(フィルタリングなどを追加する) – joakimbeng

17

あなたは、プロパティ情報を渡すためにラムダ式を使用することができます。

void DoSomething<T>(Expression<Func<T>> property) 
{ 
    var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo; 
    if (propertyInfo == null) 
    { 
     throw new ArgumentException("The lambda expression 'property' should point to a valid Property"); 
    } 
} 

は使用方法:

DoSomething(() => this.MyProperty); 
+0

インスタンスのプロパティ名( 'INotifyPropertyChanged'を実装するときに便利)のような、プロパティに関する詳細情報を取得する必要がある場合は、この方法を使用できます。しかし、これは不動産価値を返すのに十分であるため、このような状況では過労です。 –

0

ただ、上記の回答から追加します。また、注文の方向に対して単純なフラグを設定することもできます。

public class Processor 
{ 
    public List<SortableItem> SortableItems { get; set; } 

    public Processor() 
    { 
     SortableItems = new List<SortableItem>(); 
     SortableItems.Add(new SortableItem { PropA = "b" }); 
     SortableItems.Add(new SortableItem { PropA = "a" }); 
     SortableItems.Add(new SortableItem { PropA = "c" }); 
    } 

    public void SortItems(Func<SortableItem, IComparable> keySelector, bool isAscending) 
    { 
     if(isAscending) 
      SortableItems = SortableItems.OrderBy(keySelector).ToList(); 
     else 
      SortableItems = SortableItems.OrderByDescending(keySelector).ToList(); 
    } 
} 
3

@ MatthiasGの答えが見つからなかったのは、名前だけでなくプロパティの値を取得する方法です。

public static string Meth<T>(Expression<Func<T>> expression) 
{ 
    var name = ((MemberExpression)expression.Body).Member.Name; 
    var value = expression.Compile()(); 
    return string.Format("{0} - {1}", name, value); 
} 

使用:こっち

Meth(() => YourObject.Property); 
2

グレートソリューション...

Passing properties by reference in C#

void GetString<T>(string input, T target, Expression<Func<T, string>> outExpr) 
{ 
    if (!string.IsNullOrEmpty(input)) 
    { 
     var expr = (MemberExpression) outExpr.Body; 
     var prop = (PropertyInfo) expr.Member; 
     prop.SetValue(target, input, null); 
    } 
} 

void Main() 
{ 
    var person = new Person(); 
    GetString("test", person, x => x.Name); 
    Debug.Assert(person.Name == "test"); 
} 
関連する問題