diff --git a/src/Framework/Framework/Binding/DotvvmCapabilityProperty.CodeGeneration.cs b/src/Framework/Framework/Binding/DotvvmCapabilityProperty.CodeGeneration.cs index 41e03091c..a0b7500aa 100644 --- a/src/Framework/Framework/Binding/DotvvmCapabilityProperty.CodeGeneration.cs +++ b/src/Framework/Framework/Binding/DotvvmCapabilityProperty.CodeGeneration.cs @@ -192,19 +192,17 @@ public static (LambdaExpression getter, LambdaExpression setter) CreatePropertyA if (canUseDirectAccess && unwrappedType.IsValueType) { getValue = Call(typeof(Helpers), nameof(Helpers.GetStructValueDirect), new Type[] { unwrappedType }, currentControlParameter, Constant(property)); - if (type.IsNullable()) + if (!type.IsNullable()) getValue = Expression.Property(getValue, "Value"); } else { getValue = Call(currentControlParameter, getValueMethod, Constant(property), Constant(property.IsValueInherited)); + getValue = Convert(getValue, type); } return ( Expression.Lambda( - Expression.Convert( - Expression.Call(currentControlParameter, getValueMethod, Expression.Constant(property), Expression.Constant(false)), - type - ), + getValue, currentControlParameter ), Expression.Lambda( diff --git a/src/Framework/Framework/Binding/DotvvmCapabilityProperty.Helpers.cs b/src/Framework/Framework/Binding/DotvvmCapabilityProperty.Helpers.cs index 61985c9fa..ff6f5e2ad 100644 --- a/src/Framework/Framework/Binding/DotvvmCapabilityProperty.Helpers.cs +++ b/src/Framework/Framework/Binding/DotvvmCapabilityProperty.Helpers.cs @@ -101,6 +101,8 @@ public static void SetValueOrBindingSlow(DotvvmBindableObject c, DotvvmProper public static T? GetStructValueDirect(DotvvmBindableObject c, DotvvmProperty p) where T: struct { + // T being a struct allows us to invert the rather expensive `is IBinding` typecheck in EvalPropertyValue + // to a simpler is T check, as T is a single type checkable with a simple comparison if (c.properties.TryGet(p, out var x)) { if (x is null) diff --git a/src/Tests/Runtime/CapabilityPropertyTests.cs b/src/Tests/Runtime/CapabilityPropertyTests.cs index 801ae3938..eac2acee2 100644 --- a/src/Tests/Runtime/CapabilityPropertyTests.cs +++ b/src/Tests/Runtime/CapabilityPropertyTests.cs @@ -214,6 +214,28 @@ public void BitMoreComplexCapability_WeirdProperties_GetterAndSetter() Assert.AreEqual(32, controlF2.GetValue("Nullable")); } + [TestMethod] + public void BitMoreComplexCapability_InheritedProperties() + { + var control1 = new TestControlInheritedProps(); + var control2 = new TestControlInheritedProps(); + control1.Children.Add(control2); + + control1.NotNullable = 1; + control1.Nullable = 2; + + Assert.AreEqual(1, control2.NotNullable); + Assert.AreEqual(2, control2.Nullable); + + Assert.AreEqual(1, control1.GetCapability().NotNullable); + Assert.AreEqual(2, control1.GetCapability().Nullable); + Assert.AreEqual(1, control2.GetCapability().NotNullable); + Assert.AreEqual(2, control2.GetCapability().Nullable); + + control2.SetCapability(new BitMoreComplexCapability { NotNullable = 3, Nullable = null }); + Assert.AreEqual(3, control2.NotNullable); + Assert.AreEqual(null, control2.Nullable); + } [DataTestMethod] [DataRow(typeof(TestControl6))]