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

时间:2017-02-14 16:45:43

标签: c# .net 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; }
}

我创建了一个接受所有这些类的通用方法。

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);
    });
}

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

5 个答案:

答案 0 :(得分:13)

介绍界面:

 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)
     });
 }

答案 1 :(得分:7)

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

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

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

  3. 以下是一个小型测试程序来举例说明:

    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");
    }
    

    修改

    为了使它更具通用性,您只需将参数名称传递给方法:

    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);
        });
    }
    

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

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

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

    正如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);
    });
    

    修改

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

    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);
    }
    

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

答案 2 :(得分:4)

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

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

答案 3 :(得分:1)

继承将起作用

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; }
}

然后使用

而不是通用方法
public void ProcessData(IList<ABBase> param1, string date)
{
    Parallel.ForEach(T, (currentItem) =>
    {
        GetDetails(CustID )
    });
}

答案 4 :(得分:0)

  

动态

应该解决此问题,请勿投射或绕圈。

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