如何从通用方法访问类的属性 - C#

vmb*_*vmb 11 .net c# oop generics

我有一个三级,具有以下属性

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

Class B
{
    public int CustID { get; set; }
    public string Age { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个接受所有这些类的泛型方法.

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);
    });
}
Run Code Online (Sandbox Code Playgroud)

CustID属性存在于两个类中(即在A类和B类中).如何在此泛型方法中访问CustID属性?任何人都可以帮助这个

Bac*_*cks 15

介绍界面:

 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)
     });
 }
Run Code Online (Sandbox Code Playgroud)

  • 你很快 但为什么这种方法现在仍然是通用的?您可以用`ICust`完全替换`T`. (3认同)

Mon*_*Zhu 11

另一种可能性是使用System.Reflection.

  1. PropertyInfo从给定类型获取T属性的名称

  2. PropertyInfo您可以使用GetValue来获取属性的相应值.

这是一个小型测试程序,用于举例说明:

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");
}
Run Code Online (Sandbox Code Playgroud)

编辑

为了使它更通用,您可以将参数名称传递给方法:

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);
    });
}
Run Code Online (Sandbox Code Playgroud)

现在您可以决定要使用的参数:

 ProceesData<ClassA>(test, "test", "Name");
Run Code Online (Sandbox Code Playgroud)

要么

 ProceesData<ClassB>(test, "test", "Age");
Run Code Online (Sandbox Code Playgroud)

正如Gusman所建议的那样,你可以通过PropertyInfo在循环之前获得一次加速来加速:

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);
});
Run Code Online (Sandbox Code Playgroud)

编辑

显然,性能似乎是一个问题.所以这是一个比较.如果您有一分钟等待,您可以自己尝试.如果我们衡量物业的访问时间:

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);
}
Run Code Online (Sandbox Code Playgroud)

免责声明:使用代码段落来衡量当时只有一个时间.不要按原样运行程序,而是每次单独测试.


Per*_*t28 5

如果您不能在现有类上引入接口或基类,另一种方法是使用动态:

public void ProceesData<T>(IList<T> param1, string date1)
{
    Parallel.ForEach(param1, (currentItem) =>
    {
          dynamic obj = currentItem; 
          int custId = obj.CustID ;
    });
}
Run Code Online (Sandbox Code Playgroud)