5 Stimmen

C# Übergabe eines Arrays von Func<T, List<myClass>> an eine Methode

Mein erster (und wirklich schrecklicher) Beitrag steht unten.

Ich versuche, ein komplettes Beispiel zu tun, was ich bekommen möchte. Ich hoffe, dies wird ein bisschen besser erklärt werden.

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Boy> boys = new List<Boy>();
            boys.Add(new Boy("Jhon", 7));
            boys.Add(new Boy("Oscar", 6));
            boys.Add(new Boy("Oscar", 7));
            boys.Add(new Boy("Peter", 5));
            ClassRoom myClass = new ClassRoom(boys);

            Console.WriteLine(myClass.ByName("Oscar").Count);  // Prints 2
            Console.WriteLine(myClass.ByYearsOld(7).Count);  // Prints 2

            // This has errors...................
            // But this is as I would like to call my BySomeConditions method....
            Console.WriteLine(  // It should print 1
                                myClass.BySomeConditions([myClass.ByName("Oscar"),
                                                          myClass.ByYearsOld(7)]
                                                        )
                             );
            Console.ReadKey();
        }

        class ClassRoom
        {
            private List<Boy> students;

            public ClassRoom(List<Boy> students)
            {
                this.students = students;
            }

            public List<Boy> ByName(string name)
            {
                return students.FindAll(x => x.Name == name);
            }
            public List<Boy> ByYearsOld(int yearsOld)
            {
                return students.FindAll(x => x.YearsOld == yearsOld);
            }

            // This has ERRORS.......................
            public List<Boy> BySomeConditions(params Func<X, List<Boy>>[] conditions)
            {
                IEnumerable<Boy> result = students;                
                foreach (var condition in conditions) {
                    // I want it ONLY be called with existent functions (ByName and/or ByYearsOld)
                    result = result.Intersect(condition(this));  
                }
            }
        }

        class Boy
        {
            public string Name { get; set; }
            public int YearsOld { get; set; }
            public Boy(string name, int yearsOld)
            {
                Name = name;
                YearsOld = yearsOld;
            }
        }
    }
}

\============== erster Beitrag ===================== Hallo,

Ich habe eine Klasse mit Methoden:

public class X
{
    private readonly List<string> myList;

    public X(List<string> paramList) // string is really an object
    {
         myList = paramList;
    }

    // Now I want this...
    public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
    {
         var result = myList;
         foreach (Func<T, List<string>> condition in conditions)
         {
               result = result.Intersect(condition(T));
         }
    }

    public List<string> check1(string S)
    {
         return myList.FindAll(x => x.FieldS == S);
    }
    public List<string> check1(int I)
    {
         return myList.FindAll(x => x.FieldI == I);
    }
}

Sorry, wenn es einige Fehler, ich habe von scrach geschrieben, um komplexe realen Fall zu vermeiden.

Ich möchte meine Methoden wie folgt aufrufen:

   X.check1("Jhon");

o

   X.check2(12);

oder ( Dies ist das Ziel meiner Frage ) :

   X.CheckConditions(X.check1("Jhon"), X.chek2(12));

Danke und Entschuldigung für mein schlechtes Beispiel...

3voto

Amy B Punkte 104656

Es ist unklar, woher Ihr T kommt.

Entspricht dies Ihren Anforderungen?

public class X<T>
{
  private List<T> myList;

  public List<T> CheckConditions(params Func<T, bool>[] conditions)
  {
    IEnumerable<T> query = myList;
    foreach (Func<T, bool> condition in conditions)
    {
      query = query.Where(condition);
    }
    return query.ToList();
  }
}

Dann später:

List<T> result = X.CheckConditions(
  z => z.FieldS == "Jhon",
  z => z.FieldI == 12
);

2voto

wsanville Punkte 36643

Sie müssen die Methodensignatur von CheckConditions akzeptiert es eine variable Anzahl von List<string> , nicht Funktionen.

public List<string> CheckConditions(params List<string>[] lists)

Der Rückgabetyp von check1 ist List<string> sein, also muss dies der Typ des Parameters sein, der CheckConditions akzeptiert.

1voto

bdukes Punkte 144019

Es gibt keinen Grund, es generisch zu machen, Sie wissen, dass Sie mit der aktuellen Instanz von X (also einreichen this anstelle der T Typ-Parameter). Sie müssen ein paar Dinge bereinigen, damit es kompiliert werden kann (return result und machen den Typ der result und die Intersect Anruf kompatibel). Sie können es wie folgt definieren:

public List<string> CheckConditions(params Func<X, List<string>>[] conditions)
{
     IEnumerable<string> result = myList;
     foreach (var condition in conditions)
     {
           result = result.Intersect(condition(this));
     }

     return result.ToList();
}

Ameise nennt es dann so:

xInstance.CheckConditions(x => x.check1("JHon"), x => x.check1(12));

Abgesehen davon bin ich mir nicht sicher, warum man nicht einfach die Ergebnisse dieser Funktionen weitergeben sollte, anstatt die eigentlichen Funktionen weiterzugeben:

public List<string> CheckConditions(params List<string>[] conditions)
{
     IEnumerable<string> result = myList;
     foreach (var condition in conditions)
     {
           result = result.Intersect(condition);
     }

     return result.ToList();
}

Rufen Sie es dann wie in Ihrem Beispiel auf, anstatt Lambda-Ausdrücke zu übergeben.

0voto

Radagast the Brown Punkte 2982

Was Sie an Ihre

X.CheckConditions

ist nicht ein Verweis auf die Funktionen, sondern der Rückgabewert ihres Aufrufs.

Wenn Sie nun eine Funktionsreferenz übergeben - sie enthält keine Parameter, es sei denn, Sie konstruieren und übergeben eine Daten-Struktur die den Funktionsverweis und die Argumente enthält, mit denen sie arbeiten soll.

In diesem Fall sind Generika nicht die Lösung. Sie sollten ein anderes Muster in Erwägung ziehen, wie z.B. das Befehlsmuster oder das Strategiemuster, bei dem Sie an Ihre CheckConstruction Instanzen von Checker-Objekten, die jeweils mit den Parametern instanziiert werden, mit denen sie arbeiten sollen, und die entweder die Validierungsfunktion implementieren oder von ihr bereitgestellt werden.

0voto

Rune FS Punkte 20934

Könnten Sie Ihre Funktion wie folgt umschreiben:

// Now I want this...
    public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
    {
         var result = myList;
         foreach (Func<T, List<string>> condition in conditions)
         {
               result = result.Intersect(condition(T));
         }
    }

Ihr Anruf würde dann lauten X.CheckConditions(()=>X.check1("Jhon"), ()=>X.chek2(12));

und Sie müssen eine Instanz für x bereitstellen (da die Methoden Instanzmethoden und keine statischen Methoden sind)

In Ihrem Beispiel übergeben Sie T als Argument an den Funktor, aber T ist ein Typargument und kann nicht als Argument an die Methode übergeben werden. Wollten Sie einen Wert übergeben?

Dies erfordert eine Klärung der Frage, warum Sie dies tun wollen. Wenn Sie genauer beschreiben würden, was Sie erreichen wollen (im Gegensatz zum Wie), könnten Sie vielleicht eine bessere Lösung für Ihr Problem finden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X