Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 2 [3] 4   вперед  Ctrl      все
 Re: Интересная задачка, C# 3.0  [new]
googman
Member

Откуда:
Сообщений: 118
Oopss...
            // загрустил
            Console.WriteLine(TestClass.CalcMaxValue(new List<object> { 1, "gg", true }).ToString());
            // !!!!????
автор
и кому это действительно может пригодится?


Забавно, что Вы меня пытаетесь на чем-то подловить. Данная реализация не претендует на звание искуственного интеллекта, самоопределяющего методику сортировки, как кто-то замечал ранее, класса "пирожок" с классом "строка".

Однако же, это прекрасно работает в случае, когда в колекции находятся элементы одного и того же типа, наследующие IComparable. Не упомянул я этого лишь потому, что это и так понятно любому человеку, не ставящему перед собой цель подловить автора на недосказанности, многозначнительности формулировки и т.п.

Пригодится это решение может программисту C#, перед которым стоит похожая задача. Я неоднократно упоминал, что пример надуманный и упрощенный. Очень жаль, что некоторые увидели в нем смысл лишь в том, как подсчитать сумму чисел (как в стартовом посте топика) или в том, как подсчитать максимальное значение объектов, реализующих IComparable.

Конкретно у меня была следующая задача:
Был написан перегруженный Generic- Extension- метод к IQueryable<T> OrderBy, реализующий сортировку* по любому полю объекта в коллекции и принимающий имя поля в качестве параметра.

Необходимо было написать функцию, принимающую в качестве параметров коллекцию IQueryable (не IQueryable<T>) и имя поля в объекте для сортировки**, т.е. нетипизированную, определить тип элемента*** в коллекции, привести коллекцию к типу IQueryable<T> и вызвать метод OrderBy.

Сноски для любителей выискивать неоднозначности (уверен, что таковые все равно будут найдены):
* Понятно, что будет вызвано исключение, если тип сортируемого поля в объекте не реализует IComparable
** см. одну звездочку
*** Подразумевается, что элементы в коллекции будут одного и того же типа

зы
Я все-таки так понял, что у него в реальности нетипизированные коллекции. Знал бы тип - проблем бы не было :)

Именно!
30 окт 08, 23:09    [6378937]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
Oopss...

 
            // загрустил
            Console.WriteLine(TestClass.CalcMaxValue(new List<object> { 1, "gg", true }).ToString());
            // !!!!????
как его решение помогло ему в этом?

ну это твоя частная фантазия, не имеющая отношения к делу.
тут ясно описаны условия, что это список с однотипными данными, но тип списка неизвестен (обезличенный IEnumerable).
30 окт 08, 23:13    [6378941]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
googman

Конкретно у меня была следующая задача:
Был написан перегруженный Generic- Extension- метод к IQueryable<T> OrderBy, реализующий сортировку* по любому полю объекта в коллекции и принимающий имя поля в качестве параметра.

Необходимо было написать функцию, принимающую в качестве параметров коллекцию IQueryable (не IQueryable<T>) и имя поля в объекте для сортировки**, т.е. нетипизированную, определить тип элемента*** в коллекции, привести коллекцию к типу IQueryable<T> и вызвать метод OrderBy.

у меня закралось маленькое подозрение, и, чтобы его развеять, не мог бы ты запостить реализацию и код с примером её использования, которая бы решала именно описанную тобой проблему, а не то, что обсуждалось в этом топике с самого начала :)
30 окт 08, 23:17    [6378956]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
googman
Member

Откуда:
Сообщений: 118
зы
googman

Конкретно у меня была следующая задача:
Был написан перегруженный Generic- Extension- метод к IQueryable<T> OrderBy, реализующий сортировку* по любому полю объекта в коллекции и принимающий имя поля в качестве параметра.

Необходимо было написать функцию, принимающую в качестве параметров коллекцию IQueryable (не IQueryable<T>) и имя поля в объекте для сортировки**, т.е. нетипизированную, определить тип элемента*** в коллекции, привести коллекцию к типу IQueryable<T> и вызвать метод OrderBy.

у меня закралось маленькое подозрение, и, чтобы его развеять, не мог бы ты запостить реализацию и код с примером её использования, которая бы решала именно описанную тобой проблему, а не то, что обсуждалось в этом топике с самого начала :)


Код выложу завтра, т.к. он на рабочей машине.
А подозрение в чем? Что описанную задачу решаю а-ля "из пушки по воробьям"?
30 окт 08, 23:21    [6378969]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
ну типа того... кроме того я так и не понял проблемы, поскольку у тебя описание начинается с "был написан", а заканчивается "надо написать ... (далее неопределенная последовательность действий)"

конкретно проблема была - написать OrderBy<T>(string propertyName) ? или написать что-то другое?
30 окт 08, 23:26    [6378981]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
Oopss...
Guest
автор
Забавно, что Вы меня пытаетесь на чем-то подловить. Данная реализация не претендует на звание искуственного интеллекта, самоопределяющего методику сортировки, как кто-то замечал ранее, класса "пирожок" с классом "строка".

Однако же, это прекрасно работает в случае, когда в колекции находятся элементы одного и того же типа, наследующие IComparable. Не упомянул я этого лишь потому, что это и так понятно любому человеку, не ставящему перед собой цель подловить автора на недосказанности, многозначнительности формулировки и т.п.

Пригодится это решение может программисту C#, перед которым стоит похожая задача. Я неоднократно упоминал, что пример надуманный и упрощенный. Очень жаль, что некоторые увидели в нем смысл лишь в том, как подсчитать сумму чисел (как в стартовом посте топика) или в том, как подсчитать максимальное значение объектов, реализующих IComparable.

1. самое главное - никого я не цепляю - не нужно обобщать - мне просто самому стало интересно...
автор
Необходимо было написать функцию, принимающую в качестве параметров коллекцию IQueryable (не IQueryable<T>) и имя поля в объекте для сортировки**, т.е. нетипизированную, определить тип элемента*** в коллекции, привести коллекцию к типу IQueryable<T> и вызвать метод OrderBy.

2. ИМХО за всеми этими словами скрывается что-то недодуманное:
а) см. выделенное в своих словах выше
б) смотри, только что попробовал
Sub Main()

        Dim m As New ArrayList
        m.Add(1)
        m.Add(2)
        m.Add(3)

        Dim mm = From f In m _
                 Where f >= 2 _
                 Select f

        Console.WriteLine(gm(mm))

        Console.ReadLine()

    End Sub

    Private Function gm(Of T)(ByVal en As IEnumerable(Of T)) As String
        Return en.Max.ToString
    End Function
прекрасно отрабатывает...

пс. Вот тут для меня и становится интересным - зачем все эти телодвижения?

to зы -
автор
ну это твоя частная фантазия, не имеющая отношения к делу.
тут ясно описаны условия, что это список с однотипными данными, но тип списка неизвестен (обезличенный IEnumerable).

Угу - см. пример в этом посте nr.1 - какой тип там будет?
+ а вот так
        Dim m As New ArrayList
        m.Add("dfbvasdfvsd")
        m.Add("dega")
        m.Add("ggg")
        m.Add("dd")

        Dim mm = From f In m _
                 Where f >= "aa" _
                 Select f
       
        Console.WriteLine(gm(mm))
        Console.ReadLine()

    End Sub

    Private Function gm(Of T)(ByVal en As IEnumerable(Of T)) As String
        Return en.Max.ToString
    End Function

Успехов Вам всем... Сильно голову не напрягайте, а то она (голова) может сломаться с рефлекшн and etc.
30 окт 08, 23:37    [6379000]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
я вседа знал, что VB до добра не доводит
на шарпе ты такого не напишешь
автор
Could not find an implementation of the query pattern for source type 'System.Collections.ArrayList'. 'Where' not found. Consider explicitly specifying the type of the range variable 'f'.
30 окт 08, 23:42    [6379014]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
Oopss...
Guest
автор
я вседа знал, что VB до добра не доводит
на шарпе ты такого не напишешь

хз... уж мне точно лень искать, как это всё будет на си
            ArrayList arr = new ArrayList();
            arr.Add(1);
            arr.Add(2);
            arr.Add(3);
            
            var query = from int s in arr
                        where s > 2
                        select s;
как то так, наверное... что изменило это волшебное int???!!!
Коллекция случайно (вдруг) стала ТИПИЗИРОВАННОЙ? ;)))
31 окт 08, 00:21    [6379067]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
Oopss...
Guest
напоследок (контрольный выстрел ;)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
   class Program
    {
       public static T CalcMaxValue<T>(IEnumerable<T> enumerable)
       {
           return enumerable.Max();
       }

        static void Main(string[] args)
        {
            ArrayList arr = new ArrayList();
            arr.Add(1);
            arr.Add(2);
            arr.Add(3);
            
            var query = from int s in arr
                        where s > 2
                        select s;

            Console.WriteLine(CalcMaxValue(query)); 
            Console.WriteLine(CalcMaxValue(new List<string>{"kk","hh","fff"}));
            Console.ReadLine();


            arr = new ArrayList();
            arr.Add("ggg");
            arr.Add("dagd");
            arr.Add("dgfasfvasv");

            var query1 = from string s in arr
                        where s.StartsWith("d")
                        select s;

            Console.WriteLine(CalcMaxValue(query1));
            Console.WriteLine(CalcMaxValue(new List<int> { 32, 115, 12, 284, 35 }));
            Console.ReadLine();
        }
    }
}
автор
хз... уж мне точно лень искать, как это всё будет на си

;))) - вот и я прикоснулся к элите С#... ;))) - забавно...
31 окт 08, 00:35    [6379087]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
Ooops, ты не вник в суть написанной (я не утверждаю что реальной, насчет этого у меня сомнения) проблемы. То, что ты написал, я предложил ещё тут, 1в1.
То что ты используешь ArrayList как первоисточник, а потом конкретизируешь его тип в выборке, равносильно простой записи:
arr.Cast<T>()

т.е. для:
 ArrayList arr = new ArrayList();
            arr.Add(1);
            arr.Add(2);
            arr.Add(3);
            
            var query = from int s in arr
                        where s > 2
                        select s;
мы имеем:
 ArrayList arr = new ArrayList();
            arr.Add(1);
            arr.Add(2);
            arr.Add(3);
            
            var query = arr.Cast<int>().Where(x=>x>2);
т.е. как только ты закастил, ты уже имеешь типизированную коллекцию, и, главная фишка, этот тип известен на этапе компиляции. Зная тип, понятно что дело нехитрое - скормить его generic-методу и посчитать результат ;-)

Описанная проблема (если, конечно, именно она является проблемой, а не результатом неверного решения) заключается в том, что на вход тебе подается черный ящик - какой-то список каких-то элементов, но каких - ты не знаешь, но знаешь только что они умеют друг с другом меряться (если не умеют, то и хрен с ним, получим эксепшен).

и... тут меня почти было накрыло альтернативным решением
	class Program
	{
		public static object CalcMaxValue(IEnumerable list)
		{
			return list.Cast<IComparable>().Max();
		}

		static void Main(string[] args)
		{
			var arr = new ArrayList();
			arr.Add("ggg");
			arr.Add("dagd");
			arr.Add("dgfasfvasv");

			Console.WriteLine(CalcMaxValue(arr));
			Console.WriteLine(CalcMaxValue(new List<int> { 32, 115, 12, 284, 35 }));
			Console.ReadLine();
		}
	}
но, подлый рантайм по непонятным причинам не хочет кастить Int32 к IComparable, несмотря на то, что сам по себе он какбэ не против :)
int i = 0;
((IComparable)i).CompareTo(2);
31 окт 08, 01:49    [6379136]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
мозгам покоя не дают загадочные извращения рантайм удалось успешно натянуть, правда вот таким извратом:
namespace ConsoleApplication
{
	class Program
	{
		public static IEnumerable<IComparable> ToComparable(IEnumerable list)
		{
			foreach (var el in list)
			{
				yield return (IComparable)el;
			}
		}
		public static object CalcMaxValue(IEnumerable list)
		{
			return ToComparable(list).Max();
		}

		static void Main(string[] args)
		{
			var arr = new ArrayList();
			arr.Add("ggg");
			arr.Add("dagd");
			arr.Add("dgfasfvasv");

			Console.WriteLine(CalcMaxValue(arr));
			Console.WriteLine(CalcMaxValue(new List<int> { 32, 115, 12, 284, 35 }));
			Console.ReadLine();
		}
	}
}
даже не знаю почему, завтра слазаю рефлектором, посмотрю на Cast()
31 окт 08, 01:54    [6379140]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
Oopss...

как то так, наверное... что изменило это волшебное int???!!!
Коллекция случайно (вдруг) стала ТИПИЗИРОВАННОЙ? ;)))

я же говорю, что VB - зло шарп выводит все на чистую воду и убивает иллюзию о "волшебстве". Волшебства НЕТ, все строго типизировано и поддается здравой логике (по большей части)
31 окт 08, 02:10    [6379148]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
Oopss...
Guest
Да ладно холиварить - не суть проблемы... ;)))
Помоему, я наконец втыкнул что он хотел
Module Module1

    Sub Main()
        
        Dim myList As New ArrayList
        For i As Integer = 1 To 10
            myList.Add(New Rectangle(10, i))
        Next

        For Each g In mySort(myList)
            Console.WriteLine(g.Height.ToString & vbTab & g.Width.ToString)
        Next

        Console.ReadLine()

    End Sub

    Private Function mySort(ByVal en As IEnumerable) As IEnumerable
        'Вот здесь он напарил свою реализацию по извлечению типа данных из en
        'Перевёл всю эту лабуду en в IQueryable(Of тип извлечённых данных)
        '+ как говорит, прикрутил к этому expression по своей сортировке
        'и всё это вместо
        Return From g In en Select g Order By g.Height Descending
        'Единственное, что я провтыкал, как он вызывает свойство по имени?
        'Было бы интересно взглянуть
    End Function
   
End Module

Public Class Rectangle
  
    Public Width As Integer
    Public Height As Integer

    Public Sub New(ByVal width As Integer, ByVal height As Integer)
        Me.Width = width
        Me.Height = height
    End Sub
    
End Class
31 окт 08, 02:37    [6379161]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
Oopss...
Guest
LOL пока писал, не всё прочёл - теперь вроде всё...
Ладно, посмотрим, что он написал - будет яснее...
+ From g In en Select g как то же извлекает данные из чёрного ящика?
НО, это я так, о своём... ;)))
31 окт 08, 02:45    [6379164]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
Oopss...
Guest
автор
Ладно, посмотрим, что он написал - будет яснее...

Хотя, чё там смотреть - всё одно неверно он как-то подошёл к этому вопросу ;)))
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication2
{
   class Program
    {
        static void Main(string[] args)
        {

            ArrayList arr = new ArrayList();
            arr.Add(1);
            arr.Add(2);
            arr.Add(3);

            Console.WriteLine(myMax(arr));

            arr = new ArrayList();
            arr.Add("ggg");
            arr.Add("dagd");
            arr.Add("dgfasfvasv");

            Console.WriteLine(myMax(arr));

            Console.WriteLine(myMax(new List<string> { "ab", "zXd", "hs" }).ToString());
            Console.WriteLine(myMax(new List<char> { 'z', 'a', 'c' }).ToString());
            Console.WriteLine(myMax(new List<int> { 32, 115, 12, 284, 35 }).ToString());
            Console.WriteLine(myMax(new List<bool> { true, false }).ToString());            
            Console.ReadLine();
            
        }

        public static object myMax(IEnumerable source)
        {
            return source.Cast<object>().Select<object, object>(new Func<object, object>(_Lambda)).Max<object>();
        }

        private static object _Lambda(object f)
        {
            return f;
        }

    }
}
to зы - пример от рефлектора (спс что напомнил) - LOL - рабочий...
31 окт 08, 05:57    [6379209]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
googman
Member

Откуда:
Сообщений: 118
Господа, вот набросал тестовый код для консольного приложения.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.UI.WebControls;

namespace ConsoleApplication3
{
    public static class LinqSorter
    {
        public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string fieldName)
        {
            return OrderBy(source, fieldName, SortDirection.Ascending);
        }

        public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string fieldName, SortDirection sortDirection)
        {
            const string ORDER_BY_METHOD_NAME = "OrderBy";
            const string ORDER_BY_DESCENDING_METHOD_NAME = "OrderByDescending";
            const string PARAMETER_NAME = "Entity";

            // Получаем тип сортируемой сущности
            var type = typeof(TEntity);

            // Создаем параметр, чтобы передать в лямбда-выражение (Entity => Entity.OrderByField)
            var parameter = Expression.Parameter(type, PARAMETER_NAME);

            // Получаем свойство, по которому необходимо сортировать
            var property = type.GetProperty(fieldName);

            // Создаем выражение сортировки
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var orderByExp = Expression.Lambda(propertyAccess, parameter);

            // Получаем имя метода, который нужно вызвать, в зависимости от направления сортировки
            var methodName = sortDirection == SortDirection.Ascending ? ORDER_BY_METHOD_NAME : ORDER_BY_DESCENDING_METHOD_NAME;

            // Получаем ссылку на вызов метода
            var resultExp = Expression.Call(typeof(Queryable), methodName, 
                new[] { type, property.PropertyType },
                source.Expression, Expression.Quote(orderByExp));

            // Применяем сортировку
            return source.Provider.CreateQuery(resultExp) as IQueryable<TEntity>;
        }
    }

    public class TestTable
    {
        public IQueryable Source { get; private set; }

        public IEnumerable<string> Columns
        {
            get
            {
                return Source.ElementType.GetProperties().Select(property => property.Name);
            }
        }

        public TestTable(IQueryable source)
        {
            this.Source = source;
        }

        public void OrderBy(string fieldName, SortDirection direction)
        {
            var elementType = this.Source.ElementType;
            var elementTypes = new[] { elementType };
            var enumMethods = typeof(Enumerable).GetMethods();
            var querMethods = typeof(Queryable).GetMethods();
            var sorterMethods = typeof (LinqSorter).GetMethods();

            var sourceList = enumMethods.Where(curMethod => curMethod.Name == "ToList").First().MakeGenericMethod(elementTypes).Invoke(null, new[] { this.Source });
            var sourceQuery = (IQueryable)querMethods.Where(curMethod => curMethod.Name == "AsQueryable").First().MakeGenericMethod(elementTypes).Invoke(null, new[] { sourceList });

            var orderByMethod = sorterMethods.Where(curMethod => curMethod.Name == "OrderBy").Where(curMethod => curMethod.GetParameters().Count() > 2).First();
            var orderByGenericMethod = orderByMethod.MakeGenericMethod(new[] { elementType });
            var orderResult = orderByGenericMethod.Invoke(null, new object[] { sourceQuery, fieldName, direction });

            this.Source = (IQueryable)orderResult;
        }
    }

    public struct TestEntityCar
    {
        public string Manufacturer { get; set; }
        public string Model { get; set; }
        public DateTime DateOfBirth { get; set; }

        public override string ToString()
        {
            return string.Format("{0} {1}", this.Manufacturer, this.Model);
        }
    }

    public struct TestEntityCalculator
    {
        public string Model { get; set; }
        public bool IsScientific { get; set; }
        public int ButtonsCount { get; set; }

        public override string ToString()
        {
            return this.Model;
        }
    }

    public struct TestEntityShop
    {
        public string ShopName { get; set; }
        public int CalculatorsCount { get; set; }
        public int CarsCount { get; set; }
        public TestEntityCar BestCar { get; set; }
        public TestEntityCalculator BestCalculator { get; set; }
    }

    static class TestEntities
    {
        public static IEnumerable GetTestEntities()
        {
            return from car in GetTestCars()
                   from calc in GetTestCalculators()
                   select new
                              {
                                  CarDateOfBirth = car.DateOfBirth.AddDays(5),
                                  ScientificCar = calc.IsScientific
                              };
        }

        public static IEnumerable<TestEntityCar> GetTestCars()
        {
            yield return new TestEntityCar { Manufacturer = "Autocompany 1", DateOfBirth = new DateTime(1986, 1, 25), Model = "Model 4" };
            yield return new TestEntityCar { Manufacturer = "Autocompany 2", DateOfBirth = new DateTime(1999, 12, 14), Model = "Model 1" };
            yield return new TestEntityCar { Manufacturer = "Autocompany 3", DateOfBirth = new DateTime(2008, 4, 7), Model = "Model 3" };
            yield return new TestEntityCar { Manufacturer = "Autocompany 4", DateOfBirth = new DateTime(2004, 7, 1), Model = "Model 2" };
        }

        public static IEnumerable<TestEntityCalculator> GetTestCalculators()
        {
            yield return new TestEntityCalculator { ButtonsCount = 64, IsScientific = true, Model = "X-21" };
            yield return new TestEntityCalculator { ButtonsCount = 12, IsScientific = false, Model = "SP0" };
            yield return new TestEntityCalculator { ButtonsCount = 75, IsScientific = true, Model = "A-18" };
            yield return new TestEntityCalculator { ButtonsCount = 15, IsScientific = false, Model = "P-5" };
            yield return new TestEntityCalculator { ButtonsCount = 12, IsScientific = true, Model = "U21" };
            yield return new TestEntityCalculator { ButtonsCount = 34, IsScientific = true, Model = "AR32" };
        }

        public static IEnumerable<TestEntityShop> GetTestShops()
        {
            yield return
                new TestEntityShop
                {
                    BestCalculator =
                        new TestEntityCalculator { ButtonsCount = 12, IsScientific = false, Model = "SP0" },
                    BestCar =
                        new TestEntityCar
                        {
                            Manufacturer = "Autocompany 2",
                            DateOfBirth = new DateTime(1999, 12, 14),
                            Model = "Model 1"
                        },
                    CalculatorsCount = 15,
                    CarsCount = 20,
                    ShopName = "Shop 1"
                };
            yield return new TestEntityShop
            {
                BestCalculator =
                    new TestEntityCalculator { ButtonsCount = 64, IsScientific = true, Model = "X-21" },
                BestCar =
                    new TestEntityCar { Manufacturer = "Autocompany 3", DateOfBirth = new DateTime(2008, 4, 7), Model = "Model 3" },
                CalculatorsCount = 154,
                CarsCount = 1,
                ShopName = "Shop 2"
            };
            yield return new TestEntityShop
            {
                BestCalculator =
                    new TestEntityCalculator { ButtonsCount = 34, IsScientific = true, Model = "AR32" },
                BestCar =
                    new TestEntityCar { Manufacturer = "Autocompany 1", DateOfBirth = new DateTime(1986, 1, 25), Model = "Model 4" },
                CalculatorsCount = 22,
                CarsCount = 14,
                ShopName = "Shop 3"
            };
        }
    }

    class Program
    {
        static void Main()
        {
            Console.WriteLine("Please, type:");
            Console.WriteLine("1 - for test entities");
            Console.WriteLine("2 - for calculators");
            Console.WriteLine("3 - for cars");
            Console.WriteLine("any other text - for shops");

            var entitiesType = Console.ReadLine();

            Console.WriteLine();
            Console.WriteLine();

            TestTable table;

            switch (entitiesType)
            {
                case "1":
                    table = new TestTable(TestEntities.GetTestEntities().AsQueryable());
                    break;
                case "2":
                    table = new TestTable(TestEntities.GetTestCalculators().AsQueryable());
                    break;
                case "3":
                    table = new TestTable(TestEntities.GetTestCars().AsQueryable());
                    break;
                default:
                    table = new TestTable(TestEntities.GetTestShops().AsQueryable());
                    break;
            }

            var counter = 0;  
            foreach (var curColumn in table.Columns)
            {
                counter++;
                Console.WriteLine("{0}) {1}", counter, curColumn);
            }

            Console.WriteLine("Please, fill in column name for sort:");

            var correctColumnName = false;
            var sortColumnName = String.Empty;
            while (!correctColumnName)
            {
                sortColumnName = Console.ReadLine();
                if (table.Columns.Contains(sortColumnName))
                    correctColumnName = true;
                else
                    Console.WriteLine("This column isn't exists! Try again.");
            }

            table.OrderBy(sortColumnName, SortDirection.Ascending);
            WriteToDisplay(table);
        }

        private static void WriteToDisplay(TestTable table)
        {
            Console.WriteLine();
            foreach (var curColumn in table.Columns)
            {
                Console.Write(curColumn+"\t");
            }
            Console.WriteLine();
            Console.WriteLine();

            foreach (var curItem in table.Source)
            {
                foreach (var curColumn in table.Columns)
                {
                    Console.Write(table.Source.ElementType.GetProperty(curColumn).GetValue(curItem, null)+"\t");
                }
                Console.WriteLine();
            }
        }
    }
}

Сразу скажу, что по пропертям классов, не реализующих IComparable, сортировка, само собой, выдаст ошибку.
31 окт 08, 10:38    [6379905]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
Oopss...
LOL пока писал, не всё прочёл - теперь вроде всё...
Ладно, посмотрим, что он написал - будет яснее...
+ From g In en Select g как то же извлекает данные из чёрного ящика?
НО, это я так, о своём... ;)))

это все магия бейсика, он как-то подставляет тип :) ты просто посмотри тип переменной query, в которой сохранил запрос

Oopss...

to зы - пример от рефлектора (спс что напомнил) - LOL - рабочий...

хм да, тоже рабочий, я его правда сократил до
return source.Cast<object>().Max();
а вот собственно и объяснение "магии", бейсик собственноручно подставил туда object странно конечно что работает, ну да ладно пошел смотреть рефлектором, Max наверняка внутри себя работает с IComparable независимо от типа входящего аргумента.
31 окт 08, 11:01    [6380131]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
да, как при этом basic умудряется сравнить object с числом - хз, наверное в этом случае он туда все-таки правильно подставляет каст к int'у.
31 окт 08, 11:02    [6380152]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
аффтор, согласно нашим с Oopss последним выкладкам я немного укоротил твой код :)
ниже только основные измененные функции:

этот метод в инете найден верно я тоже оттуда же брал
	public static class LinqSorter
	{
		public static IQueryable OrderBy(this IQueryable source, string fieldName)
		{
			return OrderBy(source, fieldName, SortDirection.Ascending);
		}

		public static IQueryable OrderBy(this IQueryable source, string fieldName, SortDirection sortDirection)
		{
			const string ORDER_BY_METHOD_NAME = "OrderBy";
			const string ORDER_BY_DESCENDING_METHOD_NAME = "OrderByDescending";
			const string PARAMETER_NAME = "Entity";
			// Получаем тип сортируемой сущности
			//var type = typeof(TEntity);
			var type = source.ElementType;

			// Создаем параметр, чтобы передать в лямбда-выражение (Entity => Entity.OrderByField)
			var parameter = Expression.Parameter(type, PARAMETER_NAME);

			// Получаем свойство, по которому необходимо сортировать
			var property = type.GetProperty(fieldName);

			// Создаем выражение сортировки
			var propertyAccess = Expression.MakeMemberAccess(parameter, property);
			var orderByExp = Expression.Lambda(propertyAccess, parameter);

			// Получаем имя метода, который нужно вызвать, в зависимости от направления сортировки
			var methodName = sortDirection == SortDirection.Ascending ? ORDER_BY_METHOD_NAME : ORDER_BY_DESCENDING_METHOD_NAME;

			// Получаем ссылку на вызов метода
			var resultExp = Expression.Call(typeof(Queryable), methodName,
				new[] { type, property.PropertyType },
				source.Expression, Expression.Quote(orderByExp));

			// Применяем сортировку
			return source.Provider.CreateQuery(resultExp) as IQueryable;//<TEntity>;
		}
	}
ну и самое главное:
		public void OrderBy(string fieldName, SortDirection direction)
		{
			this.Source = this.Source.AsQueryable().OrderBy(fieldName, direction);
		}
31 окт 08, 11:20    [6380340]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
googman
Member

Откуда:
Сообщений: 118
Зы, спасибо огромное! :)

Вот я тормоз, не додумался поколдовать над методом, который "в инете найден верно". :)
31 окт 08, 11:40    [6380560]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
bured
Member

Откуда:
Сообщений: 22290
googman
Господа, вот набросал тестовый код для консольного приложения.


дал бы просто ссылку
31 окт 08, 11:57    [6380760]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
зы

даже не знаю почему, завтра слазаю рефлектором, посмотрю на Cast()

в общем он конвертит через Convert.ChangeType(), который пытается это сделать через интерфейс IConvertible, который в свою очередь не знает, как конвертить примитивный тип к интерфейсу, ибо имеет ограниченный набор вариантов

а Max все верно, дергает у объекта интерфейс IComparable и работает через него, соответственно что именно пришло на вход - фиолетово
31 окт 08, 12:08    [6380899]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
Oopss...
Guest
я, конечно, не на что не претендую
НО
раз уж речь шла о НЕТИПИЗИРОВАННЫХ коллекциях + сортировке по ИМЕНИ свойства члена этой коллекции + сортировке без реализации IComparable + СОБСТВЕННОМ сортировщике коллекции + многое\многое другое
ТО
что Вы здесь накрутили с SortDirection (не имеющим никакой смысловой нагрузки) + создание чудных Expression и всё остальное (как например невозможность отсортировать по свойству объекта находящегося в род. объекте коллекции) and etc.
Вызывает у меня опасения... ;)))
ИМХО Может всё это (Ваше ТЗ - выше выделено жирным) решается как-то более просто (например так)
Imports System.Runtime.CompilerServices

Module Module1

    Private Sub printRes(ByVal n As IEnumerable(Of Object), ByVal caption As String)
        Console.WriteLine(caption)
        Console.WriteLine()
        Console.WriteLine(String.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}", Space(1), "Name", "Age", "DT", "r.Height", "r.Width"))
        Console.WriteLine("-----------------------")
        For Each p In n
            Console.WriteLine(String.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}", vbTab, p.Name, p.Age, p.dt, p.r.Height, p.r.Width))
        Next
        Console.WriteLine()
        Console.WriteLine("Press Enter...")
        Console.ReadLine()
    End Sub

    Sub Main()

        Dim myList As New ArrayList
        For i As Integer = 1 To 10
            myList.Add(New Pet With {.Age = 11 - i, .Name = "myPet" & i.ToString, .dt = Now.AddDays(-i), .r = New Rectangle(i + 2, i - 25)})
        Next

        printRes(myList.myQOrderBy("Name"), "Sort ByName Asc")
        printRes(myList.myQOrderByDescending("Name"), "Sort ByName Desc")

        printRes(myList.myQOrderBy("Age"), "Sort ByAge Asc")
        printRes(myList.myQOrderByDescending("Age"), "Sort ByAge Desc")

        printRes(myList.myQOrderBy("dt"), "Sort Bydt Asc")
        printRes(myList.myQOrderByDescending("dt"), "Sort Bydt Desc")

        printRes(myList.myQOrderBy("r.Height"), "Sort ByRectHeigt Asc")
        printRes(myList.myQOrderByDescending("r.Height"), "Sort ByRect Desc")

        printRes(myList.myQOrderBy("r.Width"), "Sort ByRectWidth Asc")
        printRes(myList.myQOrderByDescending("r.Width"), "Sort ByRectWidth Desc")

    End Sub

    Friend prop As String
    <Extension()> _
    Public Function myQOrderByDescending(ByVal source As IEnumerable, ByVal P As String) As IEnumerable(Of Object)
        prop = P
        Return source.Cast(Of Object)().OrderByDescending(AddressOf _Lambda)
    End Function
    <Extension()> _
    Public Function myQOrderBy(ByVal source As IEnumerable, ByVal P As String) As IEnumerable(Of Object)
        prop = P
        Return source.Cast(Of Object)().OrderBy(AddressOf _Lambda)
    End Function

    Private Function _Lambda(ByVal r As Object) As Object
        For Each s In prop.Split(".")
            r = Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(RuntimeHelpers.GetObjectValue(r), Nothing, s, Nothing, Nothing, Nothing, Nothing)
        Next
        Return r
    End Function
End Module

Public Structure Pet
    Public Name As String
    Public Age As Integer
    Public dt As DateTime
    Public r As Rectangle
End Structure

Public Class Rectangle
    Public Width As Integer
    Public Height As Integer

    Public Sub New(ByVal width As Integer, ByVal height As Integer)
        Me.Width = width
        Me.Height = height
    End Sub
End Class
???!!! Или НЕ-А... ?

пс. Вообще было интересно поучаствовать в теме - много для себя узнал (с помощью и без ;)
31 окт 08, 16:52    [6383816]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
не-не-не, магия бейсика нам не нужна
r = Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(RuntimeHelpers.GetObjectValue(r), Nothing, s, Nothing, Nothing, Nothing, Nothing)
31 окт 08, 17:01    [6383905]     Ответить | Цитировать Сообщить модератору
 Re: Интересная задачка, C# 3.0  [new]
зы
Member

Откуда:
Сообщений: 2530
в общем насчет кастинга к object и использование OrderBy с лямбдой, возвращающей object - тут есть нюанс. Данный метод с созданием экспрешшенов и всем таким был создан не просто так, в случае с LINQ 2 SQL работает только он, иначе linq2sql адаптер не может перевести работу с object на SQL язык. Ну вот не может и все тут :) иначе все было бы просто.
31 окт 08, 17:05    [6383932]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 2 [3] 4   вперед  Ctrl      все
Все форумы / WinForms, .Net Framework Ответить