3

オブジェクトの任意のプロパティにデータを入力し、指定されたプロパティに一致するオブジェクトをコレクションで検索できるようにしたいと考えています。

class Program
{
    static List<Marble> marbles = new List<Marble> { 
        new Marble {Color = "Red", Size = 3},
        new Marble {Color = "Green", Size = 4},
        new Marble {Color = "Black", Size = 6}
    };

    static void Main()
    {
        var search1 = new Marble { Color = "Green" };
        var search2 = new Marble { Size = 6 };
        var results = SearchMarbles(search1);
    }

    public static IEnumerable<Marble> SearchMarbles(Marble search)
    {
        var results = from marble in marbles
                      //where ???
                      //Search for marbles with whatever property matches the populated properties of the parameter
                      //In this example it would return just the 'Green' marble
                      select marble;
        return results;
    }

    public class Marble
    {
        public string Color { get; set; }
        public int Size { get; set; }
    }

}
4

7 に答える 7

5

確かに、それは面白くて時間がかかります。searchまず、デフォルト値とは異なる値を持つオブジェクトのすべてのプロパティを取得する必要があります。このメソッドは、リフレクションを使用して一般的です。

var properties = typeof (Marble).GetProperties().Where(p =>
                {
                    var pType = p.PropertyType;
                    var defaultValue = pType.IsValueType 
                            ? Activator.CreateInstance(pType) : null;

                    var recentValue = p.GetValue(search);

                    return !recentValue.Equals(defaultValue);
                });

次に、LINQAllを使用して以下をフィルタリングできます。

var results = marbles.Where(m => 
                         properties.All(p => 
                         typeof (Marble).GetProperty(p.Name)
                                        .GetValue(m) == p.GetValue(search)));

追伸:このコードはテスト済みです

于 2012-09-23T17:44:26.690 に答える
2

次のような別のFilterクラスを使用できます。

class Filter
{
    public string PropertyName { get; set; }
    public object PropertyValue { get; set; }

    public bool Matches(Marble m)
    {
        var T = typeof(Marble);
        var prop = T.GetProperty(PropertyName);
        var value = prop.GetValue(m);
        return value.Equals(PropertyValue);
    }
}

このフィルターは次のように使用できます。

var filters = new List<Filter>();
filters.Add(new Filter() { PropertyName = "Color", PropertyValue = "Green" });

//this is essentially the content of SearchMarbles()
var result = marbles.Where(m => filters.All(f => f.Matches(m)));

foreach (var r in result)
{
    Console.WriteLine(r.Color + ", " + r.Size);
}

DependencyPropertiesを使用して、プロパティ名の入力をなくすことができます。

于 2012-09-23T17:21:08.573 に答える
2

任意の数のプロパティと任意のオブジェクトで機能する一般的なソリューションを提案します。また、Linq-To-Sqlコンテキストでも使用できます。SQLに適切に変換されます。

まず、指定された値が未設定として扱われるかどうかをテストする関数を定義することから始めます。例:

static public bool IsDefault(object o)
{
    return o == null || o.GetType().IsValueType && Activator.CreateInstance(o.GetType()).Equals(o);
}

search次に、オブジェクトに設定されているすべてのプロパティの値に対してテストを行うLambda式を作成する関数を作成します。

static public Expression<Func<T, bool>> GetComparison<T>(T search)
{
    var param = Expression.Parameter(typeof(T), "t");

    var props = from p in typeof(T).GetProperties()
                where p.CanRead && !IsDefault(p.GetValue(search, null))
                select Expression.Equal(
                    Expression.Property(param, p.Name),
                    Expression.Constant(p.GetValue(search, null))
                );

    var expr = props.Aggregate((a, b) => Expression.AndAlso(a, b));
    var lambda = Expression.Lambda<Func<T, bool>>(expr, param);         
    return lambda;
} 

私たちはそれをどのようにでも使うことができますIQueryable

public static IEnumerable<Marble> SearchMarbles (Marble search)
{
    var results = marbles.AsQueryable().Where(GetComparison(search));
    return results.AsEnumerable();
}   
于 2012-09-23T22:47:33.037 に答える
1

Color == nullプロパティがデフォルト値(つまり、Size == 0)を持っている場合、プロパティが入力されていないと仮定します。

var results = from marble in marbles
              where (marble.Color == search.Color || search.Color == null)
                 && (marble.Size == search.Size || search.Size == 0)
              select marble;
于 2012-09-23T16:52:00.443 に答える
1

Marblesクラスでequalsをオーバーライドできます

public override bool Equals(object obj)
    {
        var other = obj as Marble;

        if (null == other) return false;

        return other.Color == this.color && other.size == this.size; // (etc for your other porperties
    }

そして、あなたはで検索することができます

return marbles.Where(m => search == m);
于 2012-09-23T17:01:51.137 に答える
0

リフレクションを使用すると、このメソッドは、プロパティの数やタイプに関係なく、すべてのタイプで機能します。

入力されていないプロパティはスキップされます(参照型の場合はnull、値型の場合はデフォルト値)。一致しない記入済みの2つのプロパティが見つかった場合、falseが返されます。入力されたすべてのプロパティが等しい場合、trueを返します。

IsPartialMatch(object m1, object m2)
{
    PropertyInfo[] properties = m1.GetType().GetProperties();
    foreach (PropertyInfo property in properties)
    {
        object v1 = property.GetValue(m1, null);
        object v2 = property.GetValue(m2, null);
        object defaultValue = GetDefault(property.PropertyType);

        if (v1.Equals(defaultValue) continue;
        if (v2.Equals(defaultVAlue) continue;
        if (!v1.Equals(v2)) return false;
    }

    return true;
}

あなたの例にそれを適用するには

public static IEnumerable<Marble> SearchMarbles(Marble search)
{
    return marbles.Where(m => IsPartialMatch(m, search))
}

GetDefault()はこの投稿のメソッドであり、プログラムではdefault(Type)と同等です。

于 2012-09-23T17:31:46.660 に答える
0

特定のプロパティをターゲットにしないようにする場合は、リフレクションを使用できます。型のデフォルト値を返す関数を定義することから始めます(簡単な解決策についてはここを、より複雑なものについてはここを参照してください)。

次に、MarbleインスタンスをMarbleフィルターとして受け取るクラスにメソッドを記述できます。

public bool MatchesSearch(Marble search) {
    var t = typeof(Marble);
    return !(
        from prp in t.GetProperties()
        //get the value from the search instance
        let searchValue = prp.GetValue(search, null)
        //check if the search value differs from the default
        where searchValue != GetDefaultValue(prp.PropertyType) &&
              //and if it differs from the current instance
              searchValue != prp.GetValue(this, null)
        select prp
    ).Any();
}

次に、次のようにSearchMarblesなります。

public static IEnumerable<Marble> SearchMarbles(Marble search) {
    return
        from marble in marbles
        where marble.MatchesSearch(search)
        select marble;
}
于 2012-09-23T17:52:45.267 に答える