57

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

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プロパティの受け渡しを実装するためのより洗練された方法を提案してください。IMHOを使用するための最良のオプションは次のとおりです(またはこのようなもの):

vehicles = sortBy(vehicles, Class1.maxSpeed);
4

7 に答える 7

79

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

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;
    }
}

今、あなたはこのようにソートすることができます

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

だけでなく、

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

最初のパラメーターは、次のICollection<T>2つの条件を満たす必要があるため、宣言したことに注意してください。

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

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


これまで、プロパティを読み取る方法を示してきました。メソッドがプロパティを設定する必要がある場合は、セッターデリゲートも渡す必要があります

void ReadAndWriteProperty(Func<Class1, T> getProp, Action<Class1, T> setProp)

Tプロパティのタイプはどこにありますか。

于 2012-06-24T16:01:57.693 に答える
40

ラムダ式を使用して、プロパティ情報を渡すことができます。

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);
于 2012-06-24T16:02:53.060 に答える
18

@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);
于 2015-10-07T12:32:26.587 に答える
6

ここの素晴らしい解決策...

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");
}
于 2017-10-15T18:46:19.333 に答える
3

これにLinqを使用してみませんか?好き:

vehicles.OrderBy(v => v.maxSpeed).ToList();
于 2012-06-24T15:59:56.103 に答える
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();
    }
}
于 2012-06-24T16:15:23.833 に答える
0

シンプルでわかりやすい答えを出したいと思います。

関数のパラメーターは次のとおりです。System.Func<class, type of the property>

そして、次のようにプロパティを渡します。Function(x => x.Property);

コードは次のとおりです。

class HDNData
{
    private int m_myInt;
    
    public int MyInt
    {
        get { return m_myInt; }
    }
    
    public void ChangeHDNData()
    {
        if (m_myInt == 0)
            m_myInt = 69;
        else
            m_myInt = 0;
    }
}

static class HDNTest
{
    private static HDNData m_data = new HDNData();
    
    public static void ChangeHDNData()
    {
        m_data.ChangeHDNData();
    }
    
    public static void HDNPrint(System.Func<HDNData, int> dataProperty)
    {
        Console.WriteLine(dataProperty(m_data));//Print to console the dataProperty (type int) of m_data
    }
}

//******Usage******
HDNTest.ChangeHDNData();
//This is what you want: Pass property itself (which is MyInt) to function as parameter in C#
HDNTest.HDNPrint(x => x.MyInt);
于 2020-09-03T04:15:28.710 に答える