Avatar billede lasserasch Juniormester
18. januar 2014 - 11:02 Der er 10 kommentarer

Sortering af generisk liste baseret på flere properties.

Hejsa.

Hurtigt spørgsmål :

Jeg en job klasse. Ex:

    public class Job
    {
        public string Title { get; set; }
        public string Latitude { get; set; }
        public string Longitude { get; set; }
        public string City { get; set; }
        public Country Country { get; set; }
        public Company Company { get; set; }
        public Area Area { get; set; }
        public string StartDate { get; set; }
        public string EndDate { get; set; }
        public string SapID { get; set; }

    }

Jeg har så en generisk liste med 2000 jobs i.

I en metode skal jeg kunne finde jobs frem, som passer på bestemte værdier.

Ex.:

public object GetVacancies(string Continent, string Country, string Company, string Jobfunction, string freetext)
        {
            SapService service = new Common.Services.SapService();
            var source = new JobWrapper(service.Vacancies());
            var result = new List<Job>();

           
        }



Noget i den stil.

Mit spørgsmål er så :

Hvis en af de string parametre som sendes med er tomme, så skal de selvfølgelig ikke bruges til at filtrere med.

Jeg går næsten ud fra at man kan bruge en smart linq metode til at lave den filtrering.

Hvis alle parametre havde haft værdier, så ville jeg have lavet min filtrering med .Where() eller .Select()

Men findes der ikke en smart måde at håndtere de her tomme strenge på? Så man kan lave en filtrering, som kan finde ud af at ignorere filtreringen på en specifik property, såfremt filter strengen (parametren) er tom?

Håber det giver mening.

Mvh.
Lasse
Avatar billede Syska Mester
18. januar 2014 - 11:19 #1
if(!string.IsNullOrEmpty(Continent))
    list = list.Where(x => x.Continent == Continent)

Osv ... vist eneste måde jeg kender til.


Kan du så få lowercase på dine parametre til din method, så kan kan kende forskel på properties og parametre :-)
Avatar billede lasserasch Juniormester
18. januar 2014 - 11:21 #2
For yderligere at beskrive, så vil dette være det slut resultat jeg gerne vil opstå (uden dog at have testet det overhovedet).

Det tænker jeg bare at man da må kunne korte ned og skrive noget smart linq til i stedet for.

I dette eksempel er der kun få properties, men hvad nu hvis der var 100. Det ville jo være forfærdeligt....


public object GetVacancies(string Continent, string Country, string Company, string Jobfunction, string freetext)
        {
            SapService service = new Common.Services.SapService();
            var source = new JobWrapper(service.Vacancies());
            var result = source.Jobs;

            if (!string.IsNullOrEmpty(Country))
            {
                result = result.Where(job => job.Country.Name == Country).ToList();
            }
            if (!string.IsNullOrEmpty(Company))
            {
                result = result.Where(job => job.Company.Name == Company).ToList();
            }
            if (!string.IsNullOrEmpty(Jobfunction))
            {
                result = result.Where(job => job.Area.Name == Jobfunction).ToList();
            }
            if (!string.IsNullOrEmpty(freetext))
            {
                result = result.Where(    job => freetext.Trim().ToLower().Contains(job.Title.ToLower()) |
                                        job.Title.Contains(freetext.Trim().ToLower())).ToList();
            }
            return result;
        }
Avatar billede lasserasch Juniormester
18. januar 2014 - 11:24 #3
buzzzz : Ja, ups :-) Det får jeg lige rettet til... ;-)

Men ja, det er også det jeg ville gøre som sagt. Men hold da op noget kode. Igen, det her er kun et eksempel. Det vil komme flere properties.

Det skal til en funktion lidt ala den de har på edbpriser.dk til sortering og filtrering. Der kan jo potentielt være mange parametre.
Avatar billede lasserasch Juniormester
18. januar 2014 - 11:29 #4
Men okay, man kunne selvfølgelig skrive en extension som tog en collection (dictionary eller lign), løb dem igennem og lavede filtreringen. Det ville gøre det lidt mere generisk fremadrettet.

Men håbede bare på at linq havde noget smart som kunne gøre det out of the box...
Avatar billede Syska Mester
18. januar 2014 - 11:37 #5
Er det in memory collection?

Problemet er jo lidt at henvise til en property som ikke længere kan vil strongly typed ...

Så det du søger er faktisk facetteret søgning. Ved ikke præcis om det kan gøres super generic ... men mon ikke ens klasse kan have en indexer så du kan tilgå properties ala:
item["continent"] == continent

Men det er jo heller ikke flot ... og med neasted properties gør det ikke sagen nemmere.

Men kan du ikke lave et Map af Func<bool, T> som du kan slå op via et navn og så måske genbruge det på tværs af søgninger.

Jeg vil i hvert fald gerne høre hvad du når frem til :-)
Avatar billede lasserasch Juniormester
18. januar 2014 - 11:44 #6
Ja det er in memory collection. Data trækkes ud af et SAP system og caches på serveren i x antal timer.

Jeg googler videre, skal nok skrive hvad jeg kommer frem til :-)
Avatar billede lasserasch Juniormester
18. januar 2014 - 16:29 #7
Nå, jeg tror jeg er endt med følgende løsning. Det er ikke testet endnu, så det er med forbehold for små fejl.

Har brugt reflection i løsningen, så skal også have lavet performance tests, men det er i hvert fald pænere kode end før.

public object GetVacancies(string country, string company, string jobfunction, string freetext)
        {
            var service = new Common.Services.SapService();
           
            var jsonSerialiser = new JavaScriptSerializer();
            var source = new JobWrapper(service.Vacancies());
            var result = source.Jobs;

            Dictionary<string, string> filters = new Dictionary<string, string>();
            filters.Add("Company.Name", company);
            filters.Add("Country.Name", country);
            filters.Add("Area.Name", jobfunction);
            filters.Add("Title", freetext);

            result.Filter(filters);

            var json = jsonSerialiser.Serialize(result);
            return json;
        }




Filter<T> er en extension som så ser således ud :


        public static void Filter<T>(this List<T> collection, Dictionary<string, string> filters)
        {
            var filteredCollections = new List<List<T>>();
            var result = new List<T>();

            foreach (var filter in filters)
            {
                var filteredCollection = new List<T>();
                foreach (var item in collection)
                {
                    PropertyInfo propertyInfo = null;
                    if (filter.Key.Contains("."))
                    {
                        Type currentType = item.GetType();
                        object value = null;
                        foreach (string propertyName in filter.Key.Split('.'))
                        {
                            if (currentType != null)
                            {
                                propertyInfo = currentType.GetProperty(propertyName);
                                if (propertyInfo != null)
                                {
                                    currentType = propertyInfo.PropertyType;
                                    value = propertyInfo.GetValue(item, null);
                                }
                            }
                        }
                        if (value != null && value.ToString().ToLower() == filter.Value.ToLower())
                        {
                            filteredCollection.Add(item);
                        }
                    }
                    else
                    {
                        propertyInfo = item.GetType().GetProperty(filter.Key, BindingFlags.Public | BindingFlags.Instance);
                    }
                    if (propertyInfo != null && !string.IsNullOrEmpty(filter.Value))
                    {
                        var propertyValue = propertyInfo.GetValue(item, null);
                        if (propertyValue.ToString().ToLower() == filter.Value.ToLower())
                        {
                            filteredCollection.Add(item);
                        }
                    }
                }
                filteredCollections.Add(filteredCollection);
            }

            foreach (var item in collection)
            {
                bool matched = true;
                foreach (var filteredCollection in filteredCollections)
                {
                    if (matched && !filteredCollection.Contains(item))
                    {
                        matched = false;
                    }
                }
                if (matched)
                {
                    result.Add(item);
                }
            }
            collection = result;
        }




Kommentar er meget velkommen. Som sagt det er et first draft :-)
Avatar billede Syska Mester
18. januar 2014 - 16:37 #8
I hvert fald Cache af alt der kan caches ... GetProperty.

Jeg ville nok heller ikke spirnge over hvis en property ikke findes ... da jeg så vil antage man har lavet en forkert implementering.

Jeg ville smide en exception.
Avatar billede arne_v Ekspert
18. januar 2014 - 22:55 #9
Det her bliver en meget lang post.

:-)

Lad os foerst tage scenariet med en enkelt klasse. Efter min bedste overbevisning boer den haandkodes lige ud af landevejen uanset antallet af properties. Det er type safe. Det performer godt. Og det boer vaere til at vedligeholder.

Jeg ville kode det lidt anderledes end ovenfor. Jeg ville lave det "database style".


using System;
using System.Collections.Generic;
using System.Linq;

namespace E
{
    public class Data
    {
        public string V1 { get; set; }
        public string V2 { get; set; }
        public override string ToString()
        {
            return string.Format("{{V1={0},V2={1}}}", V1, V2);
        }
    }
    public class Data1
    {
        public Data A { get; set; }
        public string B { get; set; }
        public string C { get; set; }
        public override string ToString()
        {
            return string.Format("{{A={0},B={1},C={2}}}", A, B, C);
        }
    }
    public static class Util
    {
        public static List<Data1> Filter(this List<Data1> lst, string av1, string av2, string b, string c)
        {
            return lst.Where(o => (o.A.V1 == (av1 ?? o.A.V1)) &&
                                  (o.A.V2 == (av2 ?? o.A.V2)) &&
                                  (o.B == (b ?? o.B)) &&
                                  (o.C == (c ?? o.C))).ToList();
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            List<Data1> lst1 = new List<Data1> { new Data1 { A = new Data { V1 = "1AV1", V2 = "1AV2" }, B = "1B", C = "1C" },
                                                new Data1 { A = new Data { V1 = "2AV1", V2 = "2AV2" }, B = "2B", C = "2C" },
                                                new Data1 { A = new Data { V1 = "3AV1", V2 = "3AV2" }, B = "3B", C = "3C" } };
            foreach(Data1 o in lst1)
            {
                Console.WriteLine(o);
            }
            foreach(Data1 o in lst1.Filter(null, "2AV2", null, null))
            {
                Console.WriteLine(o);
            }
            Console.ReadKey();
        }
    }
}


Saa er der problemet med mange klasser. Man kan naturligvis lave det paa samme maade som med en enkelt klasse. En haandkodet metode. Det virker men giver naturligvis en metode per data klasse.


using System;
using System.Collections.Generic;
using System.Linq;

namespace E
{
    public class Data
    {
        public string V1 { get; set; }
        public string V2 { get; set; }
        public override string ToString()
        {
            return string.Format("{{V1={0},V2={1}}}", V1, V2);
        }

    }
    public class Data1
    {
        public Data A { get; set; }
        public string B { get; set; }
        public string C { get; set; }
        public override string ToString()
        {
            return string.Format("{{A={0},B={1},C={2}}}", A, B, C);
        }
    }
    public class Data2
    {
        public Data D { get; set; }
        public string E { get; set; }
        public override string ToString()
        {
            return string.Format("{{D={0},E={1}}}", D, E);
        }
    }
    public static class Util
    {
        public static List<Data1> Filter(this List<Data1> lst, string av1, string av2, string b, string c)
        {
            return lst.Where(o => (o.A.V1 == (av1 ?? o.A.V1)) &&
                                  (o.A.V2 == (av2 ?? o.A.V2)) &&
                                  (o.B == (b ?? o.B)) &&
                                  (o.C == (c ?? o.C))).ToList();
        }
        public static List<Data2> Filter(this List<Data2> lst, string dv1, string dv2, string e)
        {
            return lst.Where(o => (o.D.V1 == (dv1 ?? o.D.V1)) &&
                                  (o.D.V2 == (dv2 ?? o.D.V2)) &&
                                  (o.E == (e ?? o.E))).ToList();
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            List<Data1> lst1 = new List<Data1> { new Data1 { A = new Data { V1 = "1AV1", V2 = "1AV2" }, B = "1B", C = "1C" },
                                                new Data1 { A = new Data { V1 = "2AV1", V2 = "2AV2" }, B = "2B", C = "2C" },
                                                new Data1 { A = new Data { V1 = "3AV1", V2 = "3AV2" }, B = "3B", C = "3C" } };
            List<Data2> lst2 = new List<Data2> { new Data2 { D = new Data { V1 = "4DV1", V2 = "4DV2" }, E = "4E" },
                                                new Data2 { D = new Data { V1 = "5DV1", V2 = "5DV2" }, E = "5E" },
                                                new Data2 { D = new Data { V1 = "6DV1", V2 = "6DV2" }, E = "6E" } };
            foreach(Data1 o in lst1)
            {
                Console.WriteLine(o);
            }
            foreach(Data2 o in lst2)
            {
                Console.WriteLine(o);
            }
            foreach(Data1 o in lst1.Filter(null, "2AV2", null, null))
            {
                Console.WriteLine(o);
            }
            foreach(Data2 o in lst2.Filter("6DV1", null, "6E"))
            {
                Console.WriteLine(o);
            }
            Console.ReadKey();
        }
    }
}


Jeg foretraekker faktisk en anden variant af dette, hvor metoden flyttes ind i klassen og der er et interface til at sikre at den faktisk er der.


using System;
using System.Collections.Generic;
using System.Linq;

namespace E
{
    public class Data
    {
        public string V1 { get; set; }
        public string V2 { get; set; }
        public override string ToString()
        {
            return string.Format("{{V1={0},V2={1}}}", V1, V2);
        }

    }
    public class Data1 : IFiltrable
    {
        public Data A { get; set; }
        public string B { get; set; }
        public string C { get; set; }
        public override string ToString()
        {
            return string.Format("{{A={0},B={1},C={2}}}", A, B, C);
        }
        public bool Accept(Dictionary<string, string> filter)
        {
            return (A.V1 == (filter.Get("A.V1") ?? A.V1)) &&
                  (A.V2 == (filter.Get("A.V2") ?? A.V2)) &&
                  (B == (filter.Get("B") ?? B)) &&
                  (C == (filter.Get("C") ?? C));
        }
    }
    public class Data2 : IFiltrable
    {
        public Data D { get; set; }
        public string E { get; set; }
        public override string ToString()
        {
            return string.Format("{{D={0},E={1}}}", D, E);
        }
        public bool Accept(Dictionary<string, string> filter)
        {
            return (D.V1 == (filter.Get("D.V1") ?? D.V1)) &&
                  (D.V2 == (filter.Get("D.V2") ?? D.V2)) &&
                  (E == (filter.Get("E") ?? E));
        }
    }
    public interface IFiltrable
    {
        bool Accept(Dictionary<string, string> filter);
    }
    public static class Util
    {
        public static TV Get<TK, TV>(this Dictionary<TK, TV> d, TK key) where TV : class
        {
            if(d.ContainsKey(key))
            {
                return d[key];
            }
            else
            {
                return null;
            }
        }
        public static List<T> Filter<T>(this List<T> lst, Dictionary<string, string> filtervals) where T : IFiltrable
        {
            return lst.Where(o => o.Accept(filtervals)).ToList();
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            List<Data1> lst1 = new List<Data1> { new Data1 { A = new Data { V1 = "1AV1", V2 = "1AV2" }, B = "1B", C = "1C" },
                                                new Data1 { A = new Data { V1 = "2AV1", V2 = "2AV2" }, B = "2B", C = "2C" },
                                                new Data1 { A = new Data { V1 = "3AV1", V2 = "3AV2" }, B = "3B", C = "3C" } };
            List<Data2> lst2 = new List<Data2> { new Data2 { D = new Data { V1 = "4DV1", V2 = "4DV2" }, E = "4E" },
                                                new Data2 { D = new Data { V1 = "5DV1", V2 = "5DV2" }, E = "5E" },
                                                new Data2 { D = new Data { V1 = "6DV1", V2 = "6DV2" }, E = "6E" } };
            foreach(Data1 o in lst1)
            {
                Console.WriteLine(o);
            }
            foreach(Data2 o in lst2)
            {
                Console.WriteLine(o);
            }
            Dictionary<string, string> flt1 = new Dictionary<string, string>();
            flt1.Add("A.V2", "2AV2");
            foreach(Data1 o in lst1.Filter(flt1))
            {
                Console.WriteLine(o);
            }
            Dictionary<string, string> flt2 = new Dictionary<string, string>();
            flt2.Add("A.V1", "6DV1");
            flt2.Add("E", "6E");
            foreach(Data2 o in lst2.Filter(flt2))
            {
                Console.WriteLine(o);
            }
            Console.ReadKey();
        }
    }
}


Ulempen ved ovenstaaende er at det nogen gange kan vaere et problem at kraeve noget (aendre noget) af data klassen.

Det problem man loeses ved at lave en ny filter klasse per data klasses (stadig med et interface).


using System;
using System.Collections.Generic;
using System.Linq;

namespace E
{
    public class Data
    {
        public string V1 { get; set; }
        public string V2 { get; set; }
        public override string ToString()
        {
            return string.Format("{{V1={0},V2={1}}}", V1, V2);
        }

    }
    public class Data1
    {
        public Data A { get; set; }
        public string B { get; set; }
        public string C { get; set; }
        public override string ToString()
        {
            return string.Format("{{A={0},B={1},C={2}}}", A, B, C);
        }
    }
    public class Data2
    {
        public Data D { get; set; }
        public string E { get; set; }
        public override string ToString()
        {
            return string.Format("{{D={0},E={1}}}", D, E);
        }
    }
    public interface IFilter<T>
    {
        bool Accept(Dictionary<string, string> filter, T o);
    }
    public class Data1Filter : IFilter<Data1>
    {
        public bool Accept(Dictionary<string, string> filter, Data1 o)
        {
            return (o.A.V1 == (filter.Get("A.V1") ?? o.A.V1)) &&
                  (o.A.V2 == (filter.Get("A.V2") ?? o.A.V2)) &&
                  (o.B == (filter.Get("B") ?? o.B)) &&
                  (o.C == (filter.Get("C") ?? o.C));
        }
    }
    public class Data2Filter : IFilter<Data2>
    {
        public bool Accept(Dictionary<string, string> filter, Data2 o)
        {
            return (o.D.V1 == (filter.Get("D.V1") ?? o.D.V1)) &&
                  (o.D.V2 == (filter.Get("D.V2") ?? o.D.V2)) &&
                  (o.E == (filter.Get("E") ?? o.E));
        }
    }
    public static class Util
    {
        public static TV Get<TK, TV>(this Dictionary<TK, TV> d, TK key) where TV : class
        {
            if(d.ContainsKey(key))
            {
                return d[key];
            }
            else
            {
                return null;
            }
        }
        public static List<T> Filter<T>(this List<T> lst, IFilter<T> filter, Dictionary<string, string> filtervals)
        {
            return lst.Where(o => filter.Accept(filtervals, o)).ToList();
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            List<Data1> lst1 = new List<Data1> { new Data1 { A = new Data { V1 = "1AV1", V2 = "1AV2" }, B = "1B", C = "1C" },
                                                new Data1 { A = new Data { V1 = "2AV1", V2 = "2AV2" }, B = "2B", C = "2C" },
                                                new Data1 { A = new Data { V1 = "3AV1", V2 = "3AV2" }, B = "3B", C = "3C" } };
            List<Data2> lst2 = new List<Data2> { new Data2 { D = new Data { V1 = "4DV1", V2 = "4DV2" }, E = "4E" },
                                                new Data2 { D = new Data { V1 = "5DV1", V2 = "5DV2" }, E = "5E" },
                                                new Data2 { D = new Data { V1 = "6DV1", V2 = "6DV2" }, E = "6E" } };
            foreach(Data1 o in lst1)
            {
                Console.WriteLine(o);
            }
            foreach(Data2 o in lst2)
            {
                Console.WriteLine(o);
            }
            Dictionary<string, string> flt1 = new Dictionary<string, string>();
            flt1.Add("A.V2", "2AV2");
            foreach(Data1 o in lst1.Filter(new Data1Filter(), flt1))
            {
                Console.WriteLine(o);
            }
            Dictionary<string, string> flt2 = new Dictionary<string, string>();
            flt2.Add("A.V1", "6DV1");
            flt2.Add("E", "6E");
            foreach(Data2 o in lst2.Filter(new Data2Filter(), flt2))
            {
                Console.WriteLine(o);
            }
            Console.ReadKey();
        }
    }
}


Og nu kommer vi til hvor jeg vil undgaa at skulle skrive disse filter klasser ved at generere dem dynamisk.


using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

using Microsoft.CSharp;

namespace E
{
    public class Data
    {
        public string V1 { get; set; }
        public string V2 { get; set; }
        public override string ToString()
        {
            return string.Format("{{V1={0},V2={1}}}", V1, V2);
        }

    }
    public class Data1
    {
        public Data A { get; set; }
        public string B { get; set; }
        public string C { get; set; }
        public override string ToString()
        {
            return string.Format("{{A={0},B={1},C={2}}}", A, B, C);
        }
    }
    public class Data2
    {
        public Data D { get; set; }
        public string E { get; set; }
        public override string ToString()
        {
            return string.Format("{{D={0},E={1}}}", D, E);
        }
    }
    public interface IFilter<T>
    {
        bool Accept(Dictionary<string, string> filter, T o);
    }
    public static class Util
    {
        public static TV Get<TK, TV>(this Dictionary<TK, TV> d, TK key) where TV : class
        {
            if(d.ContainsKey(key))
            {
                return d[key];
            }
            else
            {
                return null;
            }
        }
        private static Dictionary<string, object> cache = new Dictionary<string, object>();
        private static void GetProperties(Type typ, string prefix, List<string> result)
        {
            foreach(PropertyInfo pi in typ.GetProperties())
            {
                string propnam = prefix + (prefix.Length > 0 ? "." : "") + pi.Name;
                if(pi.PropertyType.FullName.StartsWith("System.")) // <---- consider a better test for whether to recurse
                {
                    result.Add(propnam);
                }
                else
                {
                    GetProperties(pi.PropertyType, propnam, result);
                }
            }
        }
        private const string SOURCE_TEMPLATE = @"using System;
using System.Collections.Generic;

using {2};

namespace Gen
{{
    public class {0}Filter : IFilter<{0}>
    {{
        public bool Accept(Dictionary<string, string> filter, {0} o)
        {{
            return {1};
        }}
    }}
}}";
        private const string TEST_TEMPLATE = @"(o.{0} == (filter.Get(""{0}"") ?? o.{0}))";
        private static object GenerateFilter(Type typ)
        {
            List<string> proplist = new List<string>();
            GetProperties(typ, "", proplist);
            StringBuilder sb = new StringBuilder();
            foreach(string s in proplist)
            {
                if(sb.Length > 0)
                {
                    sb.Append(" && ");
                }
                sb.Append(string.Format(TEST_TEMPLATE, s));
            }
            string src = string.Format(SOURCE_TEMPLATE, typ.Name, sb.ToString(), typ.Namespace);
            //Console.WriteLine(src);
            CodeDomProvider comp = new CSharpCodeProvider();
            CompilerParameters param = new CompilerParameters();
            param.GenerateInMemory = true;
            param.ReferencedAssemblies.Add("System.Reflection.dll");
            param.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
            CompilerResults res = comp.CompileAssemblyFromSource(param, src);
            /*
            foreach(CompilerError line in res.Errors)
            {
                Console.WriteLine(line);
            }
            */
            Assembly asm = res.CompiledAssembly;
            return asm.CreateInstance("Gen." + typ.Name + "Filter");
        }
        public static List<T> Filter<T>(this List<T> lst, Dictionary<string, string> filtervals)
        {
            Type typ = typeof(T);
            IFilter<T> filter;
            if(cache.ContainsKey(typ.FullName))
            {
                filter = (IFilter<T>)cache[typ.FullName];
            }
            else
            {
                filter = (IFilter<T>)GenerateFilter(typ);
                cache.Add(typ.FullName, filter);
            }
            return lst.Where(o => filter.Accept(filtervals, o)).ToList();
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            List<Data1> lst1 = new List<Data1> { new Data1 { A = new Data { V1 = "1AV1", V2 = "1AV2" }, B = "1B", C = "1C" },
                                                new Data1 { A = new Data { V1 = "2AV1", V2 = "2AV2" }, B = "2B", C = "2C" },
                                                new Data1 { A = new Data { V1 = "3AV1", V2 = "3AV2" }, B = "3B", C = "3C" } };
            List<Data2> lst2 = new List<Data2> { new Data2 { D = new Data { V1 = "4DV1", V2 = "4DV2" }, E = "4E" },
                                                new Data2 { D = new Data { V1 = "5DV1", V2 = "5DV2" }, E = "5E" },
                                                new Data2 { D = new Data { V1 = "6DV1", V2 = "6DV2" }, E = "6E" } };
            foreach(Data1 o in lst1)
            {
                Console.WriteLine(o);
            }
            foreach(Data2 o in lst2)
            {
                Console.WriteLine(o);
            }
            Dictionary<string, string> flt1 = new Dictionary<string, string>();
            flt1.Add("A.V2", "2AV2");
            foreach(Data1 o in lst1.Filter(flt1))
            {
                Console.WriteLine(o);
            }
            Dictionary<string, string> flt2 = new Dictionary<string, string>();
            flt2.Add("A.V1", "6DV1");
            flt2.Add("E", "6E");
            foreach(Data2 o in lst2.Filter(flt2))
            {
                Console.WriteLine(o);
            }
            Console.ReadKey();
        }
    }
}


Dett her er rimeligt generisk. Det kraever ikke noget af data klassen. Og jeg tror at det performer godt, da al reflection overheadet og klasse generering kun sker en gang for hver data klasse - ikke ved hver kald af Filter og ikke ved hver element i liste. Til gengaeld er koden saa ikke laengere helt selvindlysende.
Avatar billede Syska Mester
22. januar 2014 - 00:09 #10
Hvis man alligevel går den vej, så er der vel også T4Templates som kan løse det ... altså med autogenerering af "kode".
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester