powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Linq, lambda, predicate.. подскажите как сделать "так"
9 сообщений из 9, страница 1 из 1
Linq, lambda, predicate.. подскажите как сделать "так"
    #39227710
Кифирчик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Уважаемые гуру, хорошо знакомые с лямбда выражениями...

есть функция, которая исходя из enum может возвращать разные таблицы, ниже упрощенный пример

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
            switch (table)
            {
                case TableEnum.A:
                    list = db.tA
                        .Where(c => c.NameA.StartsWith(filter))
                        .ToList();
                    result.Count = db.tA.Count(c => c.NameA.StartsWith(filter));
                    break;
                case TableEnum.B:
                    list = db.tB
                        .Where(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter))
                        .ToList();
                    result.Count
                        = db.tB.Count(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter));
                    break;
                case TableEnum.C:
                    list = db.tC
                        .Where(c => c.NameC.StartsWith(filter))
                        .ToList();
                    result.Count = db.tC.Count(c => c.NameC.StartsWith(filter));
                    break;
            }


здесь для каждой таблицы условие приходится писать дважды, в примере, для списка и для общего количества.
также, с результатом выполняется ряд действий, одинаковых для каждой таблицы. в реальном коде, в секции enum из 10 строк 8 повторяются.

Очень хочется то что повторяется "вынести за скобки", и оставить в switch только условие (т.е. ".Where(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter))"...)

Ниже пример, как "хочется" но на что моего мозга не хватает (((

Интуитивно понимаю что это как-то можно сделать, но не пойму как правильно (((


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace AppLamdaTest
{
    class Program
    {
        #region как работает сейчас
        static MyResult GetTable(TableEnum table, string filter)
        {
            var db = new MyDb();
            var result = new MyResult();
            IEnumerable<X> list = new List<X>();

            switch (table)
            {
                case TableEnum.A:
                    list = db.tA
                        .Where(c => c.NameA.StartsWith(filter))
                        .ToList();
                    result.Count = db.tA.Count(c => c.NameA.StartsWith(filter));
                    break;
                case TableEnum.B:
                    list = db.tB
                        .Where(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter))
                        .ToList();
                    result.Count
                        = db.tB.Count(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter));
                    break;
                case TableEnum.C:
                    list = db.tC
                        .Where(c => c.NameC.StartsWith(filter))
                        .ToList();
                    result.Count = db.tC.Count(c => c.NameC.StartsWith(filter));
                    break;
            }

            foreach (var a in list)
                result.ItemList.Add(a);

            return result;
        }
        #endregion

        #region Как хочется сделать

        // в зависимости от таблицы формируем ограничение для where
        static MyResult GetTable2(TableEnum table, string filter)
        {
             var result = new MyResult();
            var db = new MyDb();
            Expression<Func<X, bool>> predicateX = a => false;
            
            IEnumerable<X> dbTable;

            switch (table)
            {
                case TableEnum.A:
                    predicateX = a => ((A)a).NameA.StartsWith(filter);
                    dbTable = db.tA;
                    break;
                case TableEnum.B:
                    predicateX = a => ((B)a).NameB.StartsWith(filter) || ((B)a).NameB2.StartsWith(filter);
                    dbTable = db.tB;
                    break;
                case TableEnum.C:
                    predicateX = a => ((C)a).NameC.StartsWith(filter);
                    dbTable = db.tC;
                    break;
                default:
                    throw new ArgumentOutOfRangeException("table");
            }

            return GetTableGeneric<A>(db.tA.AsQueryable(), predicateX, filter);

        }
        
        // универсальная функция для всех таблиц
        static MyResult GetTableGeneric<T>(IQueryable<T> table, Expression<Func<X, bool>> predicateX, string filter) where T : X
        {
            var db = new MyDb();
            var result = new MyResult();

            //Expression<Func<A, bool>> predicateA = a => a.NameA.StartsWith(filter);
            //Expression<Func<B, bool>> predicateB = a => a.NameB.StartsWith(filter) || a.NameB2.StartsWith(filter);
            //Expression<Func<C, bool>> predicateC = a => a.NameC.StartsWith(filter);

            var tbl = table;
            if (!string.IsNullOrEmpty(filter))
            {
                tbl = table.Where(predicateX) as IQueryable<T>; // Здесь ошибка -  tbl = null
                result.Count = table.Count(predicateX);
            }
            else
            {
                result.Count = table.Count();
            }

            foreach (var a in tbl)
                result.ItemList.Add(a);

            return result;
        }
        #endregion


        static void Main(string[] args)
        {
            // как работает
            var resultA = GetTable(TableEnum.A, "");
            Console.WriteLine("Table A");
            Console.WriteLine(resultA.ToString());

            Console.WriteLine("Table B");
            var resultB = GetTable(TableEnum.B, "home");
            Console.WriteLine(resultB.ToString());

            Console.WriteLine("Table C");
            var resultC = GetTable(TableEnum.C, "tes");
            Console.WriteLine(resultC.ToString());

            Console.ReadKey();

            // как хочется но выдает ошибку
            Console.WriteLine("Table A 2");
            var resultA2 = GetTable2(TableEnum.A, "nam");
            Console.WriteLine(resultA2.ToString());

            Console.ReadKey();
        }
    }

    /// <summary>
    /// Возвращаемый результат
    /// </summary>
    public class MyResult
    {
        public List<X> ItemList = new List<X>();
        public int Count;

        public override string ToString()
        {
            var result = new StringBuilder();

            result.AppendLine(string.Format("Строк: {0}", Count));
            foreach (var item in ItemList)
                result.AppendLine(string.Format(" - cтрокa: {0}", item));

            return result.ToString();
        }
    }

    public class MyDb
    {
        public List<A> tA;
        public List<B> tB;
        public List<C> tC;

        public MyDb()
        {
            tA = new List<A>();
            tA.Add(new A(1, "name A 1"));
            tA.Add(new A(2, "name A 2"));
            tA.Add(new A(3, "name A 3"));
            tA.Add(new A(4, "name A 4"));

            tB = new List<B>();
            tB.Add(new B(1, "name B 1", "name 2 B 1"));
            tB.Add(new B(2, "name B 2", "home 2 B 2"));
            tB.Add(new B(3, "name B 3", "home 2 B 3"));
            tB.Add(new B(4, "name B 4", "name 2 B 4"));

            tC = new List<C>();
            tC.Add(new C(1, "name C 1"));
            tC.Add(new C(2, "name C 2"));
            tC.Add(new C(3, "name C 3"));
            tC.Add(new C(4, "test C 4"));
        }
    }

    public enum TableEnum
    {
        A, B, C
    }

    public class X
    {

    }

    public class A : X
    {
        public int IdA { get; set; }
        public string NameA { get; set; }

        public A(int id, string name)
        {
            IdA = id;
            NameA = name;
        }

        public override string ToString() { return string.Format("ID:{0}, Name:{1}", IdA, NameA); }

    }
    public class B : X
    {
        public int IdB { get; set; }
        public string NameB { get; set; }
        public string NameB2 { get; set; }

        public B(int id, string name, string name2)
        {
            IdB = id;
            NameB = name;
            NameB2 = name2;
        }
        public override string ToString() { return string.Format("ID:{0}, Name:{1}, Name:{2}", IdB, NameB, NameB2); }
    }
    public class C : X
    {
        public int IdC { get; set; }
        public string NameC { get; set; }

        public C(int id, string name)
        {
            IdC = id;
            NameC = name;
        }
        public override string ToString() { return string.Format("ID:{0}, Name:{1}", IdC, NameC); }
    }
}


...
Рейтинг: 0 / 0
Linq, lambda, predicate.. подскажите как сделать "так"
    #39227739
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: c#
1.
result.Count = list.Count;


Нужен ли тут result.Count ?
...
Рейтинг: 0 / 0
Linq, lambda, predicate.. подскажите как сделать "так"
    #39227837
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: c#
1.
2.
Func<T, bool> where = c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter);
list = db.tB.Where(where).ToList();

вместо T подставь нужный тип
...
Рейтинг: 0 / 0
Linq, lambda, predicate.. подскажите как сделать "так"
    #39228020
Фотография Cat2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Dima T
Код: c#
1.
result.Count = list.Count;



Нужен ли тут result.Count ?
+1
...
Рейтинг: 0 / 0
Linq, lambda, predicate.. подскажите как сделать "так"
    #39228032
Кифирчик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cat2,
Вот стараешься код упростить, чтоб более понятно было, а наоборот возникают вопросы X)
а так result.Count нужен?
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
            switch (table)
            {
                case TableEnum.A:
                    list = db.tA
                        .Where(c => c.NameA.StartsWith(filter))
                        .Skip(skipRows).Take(rows)
                        .ToList();
                    result.Count = db.tA.Count(c => c.NameA.StartsWith(filter));
                    break;
                case TableEnum.B:
                    list = db.tB
                        .Where(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter))
                        .Skip(skipRows).Take(rows)
                        .ToList();
                    result.Count
                        = db.tB.Count(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter));
                    break;
                case TableEnum.C:
                    list = db.tC
                        .Where(c => c.NameC.StartsWith(filter))
                        .Skip(skipRows).Take(rows)
                        .ToList();
                    result.Count = db.tC.Count(c => c.NameC.StartsWith(filter));
                    break;
            }
...
Рейтинг: 0 / 0
Linq, lambda, predicate.. подскажите как сделать "так"
    #39228035
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сохрани лямбду в переменную и используй ее
Код: c#
1.
2.
3.
4.
5.
6.
                    Func<int, Boolean> f = c => c.NameA.StartsWith(filter);
                    list = db.tA
                        .Where(f)
                        .Skip(skipRows).Take(rows)
                        .ToList();
                    result.Count = db.tA.Count(f);
...
Рейтинг: 0 / 0
Linq, lambda, predicate.. подскажите как сделать "так"
    #39228036
Кифирчик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.Pro
Код: c#
1.
2.
Func<T, bool> where = c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter);
list = db.tB.Where(where).ToList();

вместо T подставь нужный тип
В том то и проблема, в когда я создаю Func<> в переменную, надо знать что за тип... <T,... c.NameB - заранее не известно какой тип и какие поля у него есть.

Но, вы подтолкнули меня чтоб немного перетусовать код, и все срослось.

Спасибо всем кто откликнулся!

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace AppLamdaTest
{
    class Program
    {
        #region как работает сейчас
        static MyResult GetTable(TableEnum table, string filter)
        {
            var db = new MyDb();
            var result = new MyResult();
            IEnumerable<X> list = new List<X>();

            switch (table)
            {
                case TableEnum.A:
                    list = db.tA
                        .Where(c => c.NameA.StartsWith(filter))
                        .ToList();
                    result.Count = db.tA.Count(c => c.NameA.StartsWith(filter));
                    break;
                case TableEnum.B:
                    list = db.tB
                        .Where(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter))
                        .ToList();
                    result.Count
                        = db.tB.Count(c => c.NameB.StartsWith(filter) || c.NameB2.StartsWith(filter));
                    break;
                case TableEnum.C:
                    list = db.tC
                        .Where(c => c.NameC.StartsWith(filter))
                        .ToList();
                    result.Count = db.tC.Count(c => c.NameC.StartsWith(filter));
                    break;
            }

            foreach (var a in list)
                result.ItemList.Add(a);

            return result;
        }
        #endregion

        #region Как хочется сделать

        // в зависимости от таблицы формируем ограничение для where
        static MyResult GetTable2(TableEnum table, string filter)
        {
            var result = new MyResult();
            var db = new MyDb();
            switch (table)
            {
                case TableEnum.A:
                    Expression<Func<A, bool>> predicateA = a => a.NameA.StartsWith(filter);
                    result = GetTableGeneric<A>(db.tA.AsQueryable(), predicateA, filter);
                    break;
                case TableEnum.B:
                    Expression<Func<B, bool>> predicateB = a => a.NameB.StartsWith(filter) || a.NameB2.StartsWith(filter);
                    result = GetTableGeneric<B>(db.tB.AsQueryable(), predicateB, filter);
                    break;
                case TableEnum.C:
                    Expression<Func<C, bool>> predicateC = a => a.NameC.StartsWith(filter);
                    result = GetTableGeneric<C>(db.tC.AsQueryable(), predicateC, filter);
                    break;
            }
            return result;
        }
        
        // универсальная функция для всех таблиц
        static MyResult GetTableGeneric<T>(IQueryable<T> table, Expression<Func<T, bool>> predicateX, string filter) where T : X
        {
            var result = new MyResult();

            var tbl = table;
            if (!string.IsNullOrEmpty(filter))
            {
                tbl = table
                    .Where(predicateX)
                    ;
                result.Count = table.Count(predicateX);
            }
            else
            {
                result.Count = table.Count();
            }

            // вот в частности по этому в реале нужен Count
            // tbl = tbl.Skip(skipRows).Take(rows);

            foreach (var a in tbl)
                result.ItemList.Add(a);

            return result;
        }
        #endregion


        static void Main(string[] args)
        {
            // как работает
            var resultA = GetTable(TableEnum.A, "");
            Console.WriteLine("Table A");
            Console.WriteLine(resultA.ToString());

            Console.WriteLine("Table B");
            var resultB = GetTable(TableEnum.B, "home");
            Console.WriteLine(resultB.ToString());

            Console.WriteLine("Table C");
            var resultC = GetTable(TableEnum.C, "tes");
            Console.WriteLine(resultC.ToString());

            Console.ReadKey();

            // как хочется но выдает ошибку
            Console.WriteLine("Table A 2");
            var resultA2 = GetTable2(TableEnum.A, "nam");
            Console.WriteLine(resultA2.ToString());

            Console.WriteLine("Table B 2");
            var resultB2 = GetTable2(TableEnum.B, "home");
            Console.WriteLine(resultB2.ToString());

            Console.WriteLine("Table C 2");
            var resultC2 = GetTable2(TableEnum.C, "tes");
            Console.WriteLine(resultC2.ToString());

            Console.ReadKey();
        }
    }

    /// <summary>
    /// Возвращаемый результат
    /// </summary>
    public class MyResult
    {
        public List<X> ItemList = new List<X>();
        public int Count;

        public override string ToString()
        {
            var result = new StringBuilder();

            result.AppendLine(string.Format("Строк: {0}", Count));
            foreach (var item in ItemList)
                result.AppendLine(string.Format(" - cтрокa: {0}", item));

            return result.ToString();
        }
    }

    public class MyDb
    {
        public List<A> tA;
        public List<B> tB;
        public List<C> tC;

        public MyDb()
        {
            tA = new List<A>();
            tA.Add(new A(1, "name A 1"));
            tA.Add(new A(2, "name A 2"));
            tA.Add(new A(3, "name A 3"));
            tA.Add(new A(4, "name A 4"));

            tB = new List<B>();
            tB.Add(new B(1, "name B 1", "name 2 B 1"));
            tB.Add(new B(2, "name B 2", "home 2 B 2"));
            tB.Add(new B(3, "name B 3", "home 2 B 3"));
            tB.Add(new B(4, "name B 4", "name 2 B 4"));

            tC = new List<C>();
            tC.Add(new C(1, "name C 1"));
            tC.Add(new C(2, "name C 2"));
            tC.Add(new C(3, "name C 3"));
            tC.Add(new C(4, "test C 4"));
        }
    }

    public enum TableEnum
    {
        A, B, C
    }

    public class X
    {

    }

    public class A : X
    {
        public int IdA { get; set; }
        public string NameA { get; set; }

        public A(int id, string name)
        {
            IdA = id;
            NameA = name;
        }

        public override string ToString() { return string.Format("ID:{0}, Name:{1}", IdA, NameA); }

    }
    public class B : X
    {
        public int IdB { get; set; }
        public string NameB { get; set; }
        public string NameB2 { get; set; }

        public B(int id, string name, string name2)
        {
            IdB = id;
            NameB = name;
            NameB2 = name2;
        }
        public override string ToString() { return string.Format("ID:{0}, Name:{1}, Name:{2}", IdB, NameB, NameB2); }
    }
    public class C : X
    {
        public int IdC { get; set; }
        public string NameC { get; set; }

        public C(int id, string name)
        {
            IdC = id;
            NameC = name;
        }
        public override string ToString() { return string.Format("ID:{0}, Name:{1}", IdC, NameC); }
    }


}

...
Рейтинг: 0 / 0
Linq, lambda, predicate.. подскажите как сделать "так"
    #39228039
Кифирчик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TСохрани лямбду в переменную и используй ее
Код: c#
1.
2.
3.
4.
5.
6.
                    Func<int, Boolean> f = c => c.NameA.StartsWith(filter);
                    list = db.tA
                        .Where(f)
                        .Skip(skipRows).Take(rows)
                        .ToList();
                    result.Count = db.tA.Count(f);


Верно, но вынести за скобки хотелось больше, чтоб в итоге было примерно так

Код: c#
1.
2.
3.
4.
5.
                    list = t
                        .Where(f)
                        .Skip(skipRows).Take(rows)
                        .ToList();
                    result.Count = t.Count(f);


код запроса "унифицирован" для всех таблиц
это с одной стороны, с другой, чтоб код относительно конкретной сущности был сгруппирован в одном месте свитча
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
        static MyResult GetTable2(TableEnum table, string filter)
        {
            var result = new MyResult();
            var db = new MyDb();
            switch (table)
            {
                case TableEnum.A:
                    Expression<Func<A, bool>> predicateA = a => a.NameA.StartsWith(filter);
                    result = GetTableGeneric<A>(db.tA.AsQueryable(), predicateA, filter);
                    break;
                case TableEnum.B:
                    Expression<Func<B, bool>> predicateB = a => a.NameB.StartsWith(filter) || a.NameB2.StartsWith(filter);
                    result = GetTableGeneric<B>(db.tB.AsQueryable(), predicateB, filter);
                    break;
                case TableEnum.C:
                    Expression<Func<C, bool>> predicateC = a => a.NameC.StartsWith(filter);
                    result = GetTableGeneric<C>(db.tC.AsQueryable(), predicateC, filter);
                    break;
            }
            return result;
        }
...
Рейтинг: 0 / 0
Linq, lambda, predicate.. подскажите как сделать "так"
    #39228060
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Linq, lambda, predicate.. подскажите как сделать "так"
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]