Cómo acceder a las Propiedades de una clase desde un Método Genérico - C#
Tengo una clase de tres que tiene las siguientes propiedades
Class A
{
public int CustID { get; set; }
public string Name{ get; set; }
}
Class B
{
public int CustID { get; set; }
public string Age { get; set; }
}
Creé un método genérico que acepta todas estas clases.
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 propiedad CustID está presente en ambas clases (es decir, en la Clase A y la Clase B). ¿Cómo puedo acceder a la propiedad CustID en este método genérico? Alguien puede ayudarme en esto
Otra posibilidad sería utilizar System.Reflection
.
Obtenga
PropertyInfo
del tipo dadoT
con el nombre de la propiedadcon eso
PropertyInfo
puedes usarGetValue
para obtener el valor correspondiente de esa propiedad.
Aquí hay un pequeño programa de prueba para ejemplificar esto:
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");
}
EDITAR
Para hacerlo un poco más universal, simplemente puedes pasar el nombre del parámetro al método:
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);
});
}
Ahora puedes decidir qué parámetro quieres usar:
ProceesData<ClassA>(test, "test", "Name");
o
ProceesData<ClassB>(test, "test", "Age");
Como lo sugirió Gusman, podrías acelerar un poco obteniendo PropertyInfo
solo una vez antes del ciclo:
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);
});
EDITAR
Aparentemente el rendimiento parece ser un problema para ti. Así que aquí hay una comparación. Puedes probarlo por tu cuenta si tienes un minuto para esperar. Si medimos en el tiempo de acceso a la propiedad:
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);
}
Descargo de responsabilidad: utilice los pasajes del código para medir el tiempo solo uno a la vez. No ejecute el programa tal como está, sino cada prueba por sí sola.
Introducir interfaz:
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)
});
}
Si no puede introducir una interfaz o una clase base en sus clases existentes, otro enfoque es utilizar dinámica:
public void ProceesData<T>(IList<T> param1, string date1)
{
Parallel.ForEach(param1, (currentItem) =>
{
dynamic obj = currentItem;
int custId = obj.CustID ;
});
}