SORU
3 EYLÜL 2008, ÇARŞAMBA


IEnumerable< OrderBy;T> dinamik ETMENİZ;

Sql gibi bir dize kullanmak için izin veren bir Dinamik SERİ (OrderBy("Name, Age DESC")) örneğin sipariş için. VS2008 Examples bir örnek buldum Ne yazık ki, bu yöntem IQueryable<T>; sadece eserleri yer aldı. Almak için herhangi bir şekilde bu IEnumerable<T> işlevi var mı?

CEVAP
24 EKİM 2008, Cuma


Sadece bu ihtiyar cadı...

Dinamik ETMENİZ kütüphane olmadan bunu yapmak için, sadece aşağıdaki gibi bir kod lazım. Bu iç içe geçmiş özellikleri de dahil olmak üzere en yaygın senaryoları kapsar.

IEnumerable<T> ile çalışan almak için AsQueryable üzerinden gitmek bazı sarıcı yöntemler de ekleyebilirsiniz - ama aşağıdaki kod Expression mantık gerekli çekirdek.

    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
    {
        return ApplyOrder<T>(source, property, "OrderBy");
    }
    public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
    {
        return ApplyOrder<T>(source, property, "OrderByDescending");
    }
    public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
    {
        return ApplyOrder<T>(source, property, "ThenBy");
    }
    public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
    {
        return ApplyOrder<T>(source, property, "ThenByDescending");
    }
    static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName) {
        string[] props = property.Split('.');
        Type type = typeof(T);
        ParameterExpression arg = Expression.Parameter(type, "x");
        Expression expr = arg;
        foreach(string prop in props) {
            // use reflection (not ComponentModel) to mirror LINQ
            PropertyInfo pi = type.GetProperty(prop);
            expr = Expression.Property(expr, pi);
            type = pi.PropertyType;
        }
        Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
        LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

        object result = typeof(Queryable).GetMethods().Single(
                method => method.Name == methodName
                        && method.IsGenericMethodDefinition
                        && method.GetGenericArguments().Length == 2
                        && method.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(T), type)
                .Invoke(null, new object[] {source, lambda});
        return (IOrderedQueryable<T>)result;
   } 

Edit: olursa daha eğlenceli istiyorsanız karışımı ile dynamic - not her ne kadar o dynamic geçerlidir bu SERİ için Nesneleri (anlatım-ağaçlar için ORMs vb olabilir mi gerçekten temsil dynamic sorgular MemberExpression yok destek). Ama burada ETMENİZ için Nesneleri ile bunu yapmak için bir yol. Hashtable seçimi semantik kilitleme: olumlu bağlı olduğunu unutmayın

using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Runtime.CompilerServices;
static class Program
{
    private static class AccessorCache
    {
        private static readonly Hashtable accessors = new Hashtable();

        private static readonly Hashtable callSites = new Hashtable();

        private static CallSite<Func<CallSite, object, object>> GetCallSiteLocked(string name) {
            var callSite = (CallSite<Func<CallSite, object, object>>)callSites[name];
            if(callSite == null)
            {
                callSites[name] = callSite = CallSite<Func<CallSite, object, object>>.Create(
                            Binder.GetMember(CSharpBinderFlags.None, name, typeof(AccessorCache),
                            new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
            }
            return callSite;
        }

        internal static Func<dynamic,object> GetAccessor(string name)
        {
            Func<dynamic, object> accessor = (Func<dynamic, object>)accessors[name];
            if (accessor == null)
            {
                lock (accessors )
                {
                    accessor = (Func<dynamic, object>)accessors[name];
                    if (accessor == null)
                    {
                        if(name.IndexOf('.') >= 0) {
                            string[] props = name.Split('.');
                            CallSite<Func<CallSite, object, object>>[] arr = Array.ConvertAll(props, GetCallSiteLocked);
                            accessor = target =>
                            {
                                object val = (object)target;
                                for (int i = 0; i < arr.Length; i  )
                                {
                                    var cs = arr[i];
                                    val = cs.Target(cs, val);
                                }
                                return val;
                            };
                        } else {
                            var callSite = GetCallSiteLocked(name);
                            accessor = target =>
                            {
                                return callSite.Target(callSite, (object)target);
                            };
                        }
                        accessors[name] = accessor;
                    }
                }
            }
            return accessor;
        }
    }
    public static IOrderedEnumerable<dynamic> OrderBy(this IEnumerable<dynamic> source, string property)
    {
        return Enumerable.OrderBy<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
    }
    public static IOrderedEnumerable<dynamic> OrderByDescending(this IEnumerable<dynamic> source, string property)
    {
        return Enumerable.OrderByDescending<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
    }
    public static IOrderedEnumerable<dynamic> ThenBy(this IOrderedEnumerable<dynamic> source, string property)
    {
        return Enumerable.ThenBy<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
    }
    public static IOrderedEnumerable<dynamic> ThenByDescending(this IOrderedEnumerable<dynamic> source, string property)
    {
        return Enumerable.ThenByDescending<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
    }
    static void Main()
    {
        dynamic a = new ExpandoObject(), b = new ExpandoObject(), c = new ExpandoObject();
        a.X = "abc";
        b.X = "ghi";
        c.X = "def";
        dynamic[] data = new[] { new { Y = a },new { Y = b }, new { Y = c } };

        var ordered = data.OrderByDescending("Y.X").ToArray();
        foreach (var obj in ordered)
        {
            Console.WriteLine(obj.Y.X);
        }
    }
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Maschine Tutorials

    Maschine Tut

    15 ŞUBAT 2011
  • Numberphile

    Numberphile

    15 EYLÜL 2011
  • Ryan Billy

    Ryan Billy

    30 EKİM 2006