Quote:
Is it possible define a custom Func<TUserDataObject, int>
to get any subclass's field value ?
You need to create an expression which will use reflection to get the field value. You're also going to need to pass an instance of your class to the function so that it can determine the correct type to access.
public static Func<TUserDataObject, int> GetIdByInstance()
{
var p = Expression.Parameter(typeof(TUserDataObject), "p");
var type = Expression.Call(p, nameof(object.GetType), Array.Empty<Type>());
var field = Expression.Call(type, nameof(Type.GetField), Array.Empty<Type>(),
Expression.Constant("__id__"),
Expression.Constant(BindingFlags.NonPublic | BindingFlags.Static));
var fieldValue = Expression.Call(field, nameof(FieldInfo.GetValue), Array.Empty<Type>(), Expression.Constant(null));
var body = Expression.Convert(fieldValue, typeof(int));
var lambda = Expression.Lambda<Func<TUserDataObject, int>>(body, p);
return lambda.Compile();
}
The lambda expression will be equivalent to:
(TUserDataObject p) => (int)p.GetType().GetField("__id__", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
Which then raises the question: why are you using LINQ expressions to build the method? You could just use the lambda method directly with the same effect:
public static Func<TUserDataObject, int> GetIdByInstance()
=> (TUserDataObject p) => (int)p.GetType().GetField("__id__", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
NB: You'll want to measure the performance impact of this. Reflection is notoriously slow, so if you're changing from a
(hopefully cached) method per type to a single method that uses reflection, it will slow things down.
If you're using a relatively-recent version of .NET (7 or later), it may be better to use an interface with a
static
property to retrieve this information:
Explore static virtual members in C# interfaces | Microsoft Learn[
^]