The derivation of the type of the Lambda expression differs in the inheritance chain. What for?

Given the following classes:

public class Class1<TObject> { protected void MethodA<TType>(Expression<Func<TObject, TType>> property, ref TType store, TType value) { } } public class Class2<TObject> : Class1<Class2<TObject>>{ private int _propertyInt; public int PropertyInt { get { return _propertyInt; } set { MethodA(c2 => c2.PropertyInt, ref _propertyInt, value); } } } public class Class3 : Class2<Class3> { private float _propertyFloat; public float PropertyFloat { get { return _propertyFloat; } set { MethodA(c3 => c3.PropertyFloat, ref _propertyFloat, value); } } } 

For Class2, the C # compiler registers the generic base class type for the lambda expression in the PropertyInt property setting, but for Class3 the compiler passes the base class, not just the generic base class type. Why is this? What are the criteria for the type to be deduced in the code sample. Thanks.

+4
source share
1 answer

First, the general parameter TObject is defined in Class1. This TObject is used in Class1 as a type argument in MethodA.

In Class2, the TObject passed to the base (Class1) is class 2, so lambda can output the local _propertyInt property.

In Class3, the TObject passed to the base is Class2, not Class3. Therefore, the lambda argument is deduced, but it is deduced as Class2, not Class3.

The fact that Class2 also has a type parameter named TObject is completely the same, I think you expect that everything that is passed to this TObject will be transitively passed to Class1, but it is not.

If you defined Class3 as follows, it will work:

 public class Class3 : Class1<Class3> { ... } 

Given the comment, I can suggest this solution based on the extension method (assuming that the type parameters are only intended to do the job):

 public class Class1 { } public static class StaticClass1 { public static void MethodA<TZen, TType>(this TZen zen, Expression<Func<TZen, TType>> property, ref TType store, TType value) where TZen : Class1 { // Do whatever here... } } public class Class2 : Class1 { private int _propertyInt; public int PropertyInt { get { return _propertyInt; } set { this.MethodA(c2 => c2.PropertyInt, ref _propertyInt, value); } } } public class Class3 : Class2 { private float _propertyFloat; public float PropertyFloat { get { return _propertyFloat; } set { this.MethodA(c3 => c3.PropertyFloat, ref _propertyFloat, value); } } } 
+4
source

All Articles