Я сделал небольшой эксперимент по запуску метода «1000000000» раз с «Parallel.For» и одним с объектами «Задача».
Я измерил время процессора и нашел Parallel более эффективным. Parallel.For делит вашу задачу на небольшие рабочие элементы и выполняет их на всех ядрах в оптимальном порядке. При создании множества объектов задач (FYI TPL будет использовать пул потоков внутри) будет перемещать каждое выполнение по каждой задаче, создавая больше стресса в ящике, что видно из приведенного ниже эксперимента.
Я также создал небольшое видео, которое объясняет базовый TPL, а также продемонстрировало, как Parallel.For использует ваше ядро более эффективно http://www.youtube.com/watch?v=No7QqSc5cl8 по сравнению с обычными задачами и потоками.
Эксперимент 1
Parallel.For(0, 1000000000, x => Method1());
Эксперимент 2
for (int i = 0; i < 1000000000; i++)
{
Task o = new Task(Method1);
o.Start();
}
[/g1]
Просто споткнулся в это старое произведение...
, Чтобы сделать это без динамической библиотеки LINQ, Вам просто нужен код как ниже. Это покрывает наиболее распространенные сценарии включая вложенные свойства.
Для получения его работающий с IEnumerable<T>
Вы могли добавить некоторые методы обертки, которые идут через AsQueryable
- но код ниже является ядром Expression
необходимая логика.
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;
}
<час> Редактирование: это получает больше забавы, если Вы хотите смешать это с dynamic
- хотя примечание, которое dynamic
только относится к LINQ к объектам (деревья выражений для ORMs и т.д. не могут действительно представить dynamic
запросы - MemberExpression
, не поддерживает его). Но вот способ сделать это с LINQ к объектам. Обратите внимание, что выбор Hashtable
происходит из-за благоприятной семантики блокировки:
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);
}
}
}
Вы могли добавить его:
public static IEnumerable<T> OrderBy( this IEnumerable<T> input, string queryString) {
//parse the string into property names
//Use reflection to get and sort by properties
//something like
foreach( string propname in queryString.Split(','))
input.OrderBy( x => GetPropertyValue( x, propname ) );
// I used Kjetil Watnedal's reflection example
}
Эти GetPropertyValue
функция от ответ Kjetil Watnedal
, проблема была бы то, почему? Любой такой вид выдал бы исключения во времени выполнения, а не время компиляции (как ответ D2VIANT).
, Если Вы имеете дело с Linq к Sql и orderby, дерево выражений, это будет преобразовано в SQL для выполнения так или иначе.
У меня есть задержка этот поиск вопроса Linq несколько orderby пунктов, и возможно это было тем, что автор искал
, Вот то, как сделать это:
var query = pets.OrderBy(pet => pet.Name).ThenByDescending(pet => pet.Age);
Я предполагаю, что это работало бы для использования отражения для получения безотносительно свойства, на котором Вы хотите отсортировать:
IEnumerable<T> myEnumerables
var query=from enumerable in myenumerables
where some criteria
orderby GetPropertyValue(enumerable,"SomeProperty")
select enumerable
private static object GetPropertyValue(object obj, string property)
{
System.Reflection.PropertyInfo propertyInfo=obj.GetType().GetProperty(property);
return propertyInfo.GetValue(obj, null);
}
Примечание, что использование отражения значительно медленнее, чем доступ к свойству непосредственно, таким образом, производительность должна была бы быть исследована.
Я нашел ответ. Я могу использовать .AsQueryable<>()
дополнительный метод для преобразования моего списка в IQueryable, затем выполнить динамический порядок против него.
Альтернативное решение использует следующий класс/интерфейс. Это не действительно динамично, но это работает.
public interface IID
{
int ID
{
get; set;
}
}
public static class Utils
{
public static int GetID<T>(ObjectQuery<T> items) where T:EntityObject, IID
{
if (items.Count() == 0) return 1;
return items.OrderByDescending(u => u.ID).FirstOrDefault().ID + 1;
}
}
Просто здание, что сказали другие. Я нашел что следующие работы вполне хорошо.
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> input, string queryString)
{
if (string.IsNullOrEmpty(queryString))
return input;
int i = 0;
foreach (string propname in queryString.Split(','))
{
var subContent = propname.Split('|');
if (Convert.ToInt32(subContent[1].Trim()) == 0)
{
if (i == 0)
input = input.OrderBy(x => GetPropertyValue(x, subContent[0].Trim()));
else
input = ((IOrderedEnumerable<T>)input).ThenBy(x => GetPropertyValue(x, subContent[0].Trim()));
}
else
{
if (i == 0)
input = input.OrderByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
else
input = ((IOrderedEnumerable<T>)input).ThenByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
}
i++;
}
return input;
}
Я пытался сделать это, но у меня возникли проблемы с решением Кьетила Уотнедала , потому что я не использую встроенный синтаксис linq - я предпочитаю синтаксис в стиле метода. Моя конкретная проблема заключалась в попытке выполнить динамическую сортировку с использованием специального IComparer
.
Мое решение закончилось так:
Учитывая такой запрос IQueryable:
List<DATA__Security__Team> teams = TeamManager.GetTeams();
var query = teams.Where(team => team.ID < 10).AsQueryable();
И учитывая время выполнения аргумент поля сортировки:
string SortField; // Set at run-time to "Name"
Динамический OrderBy выглядит так:
query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField));
И здесь используется небольшой вспомогательный метод GetReflectedPropertyValue ():
public static string GetReflectedPropertyValue(this object subject, string field)
{
object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null);
return reflectedValue != null ? reflectedValue.ToString() : "";
}
И последнее - я упомянул, что хотел, чтобы OrderBy
был используйте пользовательский IComparer
- потому что я хотел сделать естественную сортировку .
Для этого я просто изменяю OrderBy
на:
Вот что-то еще, что я нашел интересным. Если ваш источник является DataTable, вы можете использовать динамическую сортировку без использования справки Dynamic Linq
DataTable orders = dataSet.Tables["SalesOrderHeader"];
EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
orderby order.Field<DateTime>("OrderDate")
select order;
DataView view = query.AsDataView();
bindingSource1.DataSource = view;
: http://msdn.microsoft.com/en-us/library/bb669083.aspx (с использованием набора данных)
Вот еще один способ сделать это, преобразуя его в DataView:
DataTable contacts = dataSet.Tables["Contact"];
DataView view = contacts.AsDataView();
view.Sort = "LastName desc, FirstName asc";
bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
Просто наткнулся на этот вопрос.
Используя реализацию Марка ApplyOrder, описанную выше, я создал метод Extension, который обрабатывает SQL-подобные строки, например:
list.OrderBy("MyProperty DESC, MyOtherProperty ASC");
Подробности можно найти здесь: http://aonnull.blogspot.com/2010/08/ динамический-sql-like-linq-orderby-extension.html