web-dev-qa-db-fra.com

Comment accéder aux propriétés d'une classe à partir d'une méthode générique - C #

J'ai une classe à trois qui a les propriétés suivantes

Class A
{
    public int CustID { get; set; }
    public string Name{ get; set; }
}

Class B
{
    public int CustID { get; set; }
    public string Age { get; set; }
}

J'ai créé une méthode générique qui accepte toutes ces classes.

public void ProceesData<T>(IList<T> param1, string date1)
{
    Parallel.ForEach(T, (currentItem) =>
    {
       // I want to aceess CustID property of param1 and pass that value to another function
        GetDetails(CustID );
        RaiseRequest<T>(param1);
    });
}

La propriété CustID est présente dans les deux classes (c'est-à-dire dans les classes A et B). Comment puis-je accéder à la propriété CustID dans cette méthode générique? Quelqu'un peut-il aider à ce sujet

12
vmb

Une autre possibilité serait d'utiliser System.Reflection.

  1. Récupère le PropertyInfo du type donné T avec le nom de la propriété

  2. avec ce PropertyInfo vous pouvez utiliser GetValue pour obtenir la valeur correspondante de cette propriété.

Voici un petit programme de test pour illustrer cela:

public class ClassA
{
      public int CustID { get; set; }
      public string Name { get; set; }
}

public class ClassB
{
      public int CustID { get; set; }
     public string Age { get; set; }
}
public static void ProceesData<T>(IList<T> param1, string date1)
{
    Parallel.ForEach(param1, (currentItem) =>
    {
        // I want to aceess CustID property of param1 and pass that value to another function
        var value = typeof(T).GetProperty("CustID").GetValue(currentItem);
        Console.WriteLine("Value: " + value);
    });
}
public static void Main(string[] args)
{
    List<ClassA> test = new List<ClassA>();

    test.Add(new ClassA { CustID = 123 });
    test.Add(new ClassA { CustID = 223 });
    test.Add(new ClassA { CustID = 323 });

    ProceesData<ClassA>(test, "test");
}

MODIFIER

Pour le rendre un peu plus universel, vous pouvez simplement passer le nom du paramètre dans la méthode:

public static void ProceesData<T>(IList<T> param1, string date1, string parameter)
{
    Parallel.ForEach(param1, (currentItem) =>
    {
        // I want to aceess CustID property of param1 and pass that value to another function
        var value = typeof(T).GetProperty(parameter).GetValue(currentItem);
        Console.WriteLine("Value: " + value);
    });
}

Vous pouvez maintenant décider quel paramètre vous souhaitez utiliser:

 ProceesData<ClassA>(test, "test", "Name");

ou

 ProceesData<ClassB>(test, "test", "Age");

Comme suggéré par Gusman, vous pouvez accélérer un peu en obtenant le PropertyInfo juste une fois avant la boucle:

PropertyInfo pi = typeof(T).GetProperty(parameter);
Parallel.ForEach(param1, (currentItem) =>
{
    // I want to aceess CustID property of param1 and pass that value to another function
    var value = pi.GetValue(currentItem);
    Console.WriteLine("Value: " + value);
});

MODIFIER

Apparemment, les performances semblent être un problème pour vous. Voici donc une comparaison. Vous pouvez l'essayer par vous-même si vous avez une minute à attendre. Si nous mesurons le temps d'accès à la propriété:

public static void ProceesDataD<T>(IList<T> param1, string date1)
{
    Parallel.ForEach(param1, (currentItem) =>
    {
        dynamic obj = currentItem;
        int custId = obj.CustID;
    });
}
public static void ProceesData<T>(IList<T> param1, string date1) where T : ICust
{
    Parallel.ForEach(param1, (currentItem) =>
    {
        var value = currentItem.CustID;
    });
}
public static void ProceesData<T>(IList<T> param1, string date1, string parameter)
{

    PropertyInfo pi = typeof(T).GetProperty(parameter);
    Parallel.ForEach(param1, (currentItem) =>
    {
        var value = pi.GetValue(currentItem);
    });
}
public static void Main(string[] args)
{
    List<ClassA> test = new List<ClassA>();
    List<A> testA = new List<A>();

    Stopwatch st = new Stopwatch();

    for (int i = 0; i < 10000; i++)
    {
        test.Add(new ClassA { CustID = 123, Name = "Me" });
        testA.Add(new A { CustID = 123, Name = "Me" });
    }       

    st.Start();
    ProceesData<ClassA>(test, "test", "CustID");
    st.Stop();
    Console.WriteLine("Reflection: " + st.ElapsedMilliseconds);

    st.Restart();
    ProceesData<A>(testA, "test");
    st.Stop();
    Console.WriteLine("Interface: " + st.ElapsedMilliseconds);

    st.Restart();
    ProceesDataD<ClassA>(test, "test");
    st.Stop();
    Console.WriteLine("Dynamic: " + st.ElapsedMilliseconds);
}

Avertissement: utilisez les passages de code pour mesurer l'heure une seule à la fois. N'exécutez pas le programme tel qu'il est, mais chaque test est isolé.

9
Mong Zhu

Présentez l'interface:

 interface ICust
 {
     public int CustID { get;}
 }
 class A : ICust
 {
     public int CustID { get; set; }
     public string Name{ get; set; }
 }

 class B : ICust
 {
     public int CustID { get; set; }
     public string Age { get; set; }
 }

 public void ProceesData<T>(IList<T> param1, string date1) where T : ICust
 {
     Parallel.ForEach(param1, (currentItem) =>
     {
         GetDetails(currentItem.CustID)
     });
 }
15
Backs

Si vous ne pouvez pas introduire d'interface ou de classe de base sur vos classes existantes, une autre approche consiste à utiliser dynamic:

public void ProceesData<T>(IList<T> param1, string date1)
{
    Parallel.ForEach(param1, (currentItem) =>
    {
          dynamic obj = currentItem; 
          int custId = obj.CustID ;
    });
}
4
Perfect28

L'héritage fonctionnera

public abstract class ABBase
{
    public int CustID { gete; set; }
}

public class A : ABBase
{
    public string Name { get; set; }
}

public class B : ABBase
{
    public string Age { get; set; }
}

Alors plutôt qu'une utilisation de méthode générique

public void ProcessData(IList<ABBase> param1, string date)
{
    Parallel.ForEach(T, (currentItem) =>
    {
        GetDetails(CustID )
    });
}
1
Barry O'Kane

dynamique

devrait résoudre ce problème, ne pas lancer ou tourner en rond ..

    List<T> products = new List<T>();
    foreach (dynamic prod in products)
    { 
        prod.ShopCategoryID = 1 ;  // give you access to props
    }
0
Mahmoud Sayed