Fixes #4162. Keyword dynamic isn't AOT-Compatible and must be removed (#4163)

This commit is contained in:
BDisp
2025-06-15 17:57:55 +01:00
committed by GitHub
parent 6e486c718e
commit b50a8fd665
4 changed files with 106 additions and 32 deletions

View File

@@ -252,7 +252,7 @@ internal class NumericUpDownEditor<T> : View where T : notnull
{
X = Pos.Center (),
Y = Pos.Bottom (_increment) + 1,
Increment = (dynamic)1,
Increment = NumericUpDown<int>.TryConvert (1, out T? increment) ? increment : default,
};
_numericUpDown.ValueChanged += NumericUpDownOnValueChanged;

View File

@@ -410,7 +410,7 @@ public class TextAlignmentAndDirection : Scenario
// Save Alignment in Data
foreach (View t in multiLineLabels)
{
t.Data = new { h = t.TextAlignment, v = t.VerticalTextAlignment };
t.Data = new TextAlignmentData (t.TextAlignment, t.VerticalTextAlignment);
}
container.Add (txtLabelTL);
@@ -594,8 +594,9 @@ public class TextAlignmentAndDirection : Scenario
foreach (View t in multiLineLabels)
{
t.TextAlignment = (Alignment)((dynamic)t.Data).h;
t.VerticalTextAlignment = (Alignment)((dynamic)t.Data).v;
var data = (TextAlignmentData)t.Data;
t.TextAlignment = data!.h;
t.VerticalTextAlignment = data.v;
}
}
else
@@ -607,24 +608,23 @@ public class TextAlignmentAndDirection : Scenario
justifyOptions.Enabled = true;
}
var data = (TextAlignmentData)t.Data;
if (TextFormatter.IsVerticalDirection (t.TextDirection))
{
switch (justifyOptions.SelectedItem)
{
case 0:
t.VerticalTextAlignment = Alignment.Fill;
t.TextAlignment = ((dynamic)t.Data).h;
t.TextAlignment = data!.h;
break;
case 1:
t.VerticalTextAlignment = (Alignment)((dynamic)t.Data).v;
t.VerticalTextAlignment = data!.v;
t.TextAlignment = Alignment.Fill;
break;
case 2:
t.VerticalTextAlignment = Alignment.Fill;
t.TextAlignment = Alignment.Fill;
break;
}
}
@@ -634,18 +634,15 @@ public class TextAlignmentAndDirection : Scenario
{
case 0:
t.TextAlignment = Alignment.Fill;
t.VerticalTextAlignment = ((dynamic)t.Data).v;
t.VerticalTextAlignment = data!.v;
break;
case 1:
t.TextAlignment = (Alignment)((dynamic)t.Data).h;
t.TextAlignment = data!.h;
t.VerticalTextAlignment = Alignment.Fill;
break;
case 2:
t.TextAlignment = Alignment.Fill;
t.VerticalTextAlignment = Alignment.Fill;
break;
}
}
@@ -653,4 +650,10 @@ public class TextAlignmentAndDirection : Scenario
}
}
}
private class TextAlignmentData (Alignment h, Alignment v)
{
public Alignment h { get; } = h;
public Alignment v { get; } = v;
}
}

View File

@@ -1,5 +1,6 @@
#nullable enable
using System.ComponentModel;
using System.Numerics;
namespace Terminal.Gui.Views;
@@ -26,13 +27,7 @@ public class NumericUpDown<T> : View where T : notnull
{
Type type = typeof (T);
if (!(type == typeof (object)
|| type == typeof (int)
|| type == typeof (long)
|| type == typeof (double)
|| type == typeof (float)
|| type == typeof (double)
|| type == typeof (decimal)))
if (!(type == typeof (object) || NumericHelper.SupportsType (type)))
{
throw new InvalidOperationException ("T must be a numeric type that supports addition and subtraction.");
}
@@ -40,8 +35,11 @@ public class NumericUpDown<T> : View where T : notnull
// `object` is supported only for AllViewsTester
if (type != typeof (object))
{
Increment = (dynamic)1;
Value = (dynamic)0;
if (NumericHelper.TryGetHelper (typeof (T), out INumericHelper? helper))
{
Increment = (T)helper!.One;
Value = (T)helper!.Zero;
}
}
Width = Dim.Auto (DimAutoStyle.Content);
@@ -106,11 +104,10 @@ public class NumericUpDown<T> : View where T : notnull
// return true;
//}
if (Value is { } && Increment is { })
if (Value is { } v && Increment is { } i && NumericHelper.TryGetHelper (typeof (T), out INumericHelper? helper))
{
Value = (dynamic)Value + (dynamic)Increment;
Value = (T)helper!.Add (v, i);
}
return true;
});
@@ -129,12 +126,10 @@ public class NumericUpDown<T> : View where T : notnull
// return true;
//}
if (Value is { } && Increment is { })
if (Value is { } v && Increment is { } i && NumericHelper.TryGetHelper (typeof (T), out INumericHelper? helper))
{
Value = (dynamic)Value - (dynamic)Increment;
Value = (T)helper!.Subtract (v, i);
}
return true;
});
@@ -248,7 +243,7 @@ public class NumericUpDown<T> : View where T : notnull
get => _increment;
set
{
if (_increment is { } && value is { } && (dynamic)_increment == (dynamic)value)
if (_increment is { } oldVal && value is { } newVal && oldVal.Equals (newVal))
{
return;
}
@@ -267,6 +262,34 @@ public class NumericUpDown<T> : View where T : notnull
// Prevent the drawing of Text
/// <inheritdoc />
protected override bool OnDrawingText () { return true; }
/// <summary>
/// Attempts to convert the specified <paramref name="value"/> to type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type to which the value should be converted.</typeparam>
/// <param name="value">The value to convert.</param>
/// <param name="result">
/// When this method returns, contains the converted value if the conversion succeeded,
/// or the default value of <typeparamref name="T"/> if the conversion failed.
/// </param>
/// <returns>
/// <c>true</c> if the conversion was successful; otherwise, <c>false</c>.
/// </returns>
public static bool TryConvert<T> (object value, out T? result)
{
try
{
result = (T)Convert.ChangeType (value, typeof (T));
return true;
}
catch
{
result = default (T);
return false;
}
}
}
/// <summary>
@@ -274,3 +297,45 @@ public class NumericUpDown<T> : View where T : notnull
/// </summary>
public class NumericUpDown : NumericUpDown<int>
{ }
internal interface INumericHelper
{
object One { get; }
object Zero { get; }
object Add (object a, object b);
object Subtract (object a, object b);
}
internal static class NumericHelper
{
private static readonly Dictionary<Type, INumericHelper> _helpers = new ();
static NumericHelper ()
{
// Register known INumber<T> types
Register<int> ();
Register<long> ();
Register<float> ();
Register<double> ();
Register<decimal> ();
// Add more as needed
}
private static void Register<T> () where T : INumber<T>
{
_helpers [typeof (T)] = new NumericHelperImpl<T> ();
}
public static bool TryGetHelper (Type t, out INumericHelper? helper)
=> _helpers.TryGetValue (t, out helper);
private class NumericHelperImpl<T> : INumericHelper where T : INumber<T>
{
public object One => T.One;
public object Zero => T.Zero;
public object Add (object a, object b) => (T)a + (T)b;
public object Subtract (object a, object b) => (T)a - (T)b;
}
public static bool SupportsType (Type type) => _helpers.ContainsKey (type);
}

View File

@@ -1,5 +1,4 @@
using System.Globalization;
using Xunit.Abstractions;
namespace Terminal.Gui.ViewsTests;
@@ -102,6 +101,13 @@ public class NumericUpDownTests
Assert.Null (exception);
}
[Fact]
public void WhenCreatedWithValidNumberType_ShouldThrowInvalidOperationException_UnlessTheyAreRegisterAsValid ()
{
Exception exception = Record.Exception (() => new NumericUpDown<short> ());
Assert.NotNull (exception);
}
[Fact]
public void WhenCreated_ShouldHaveDefaultWidthAndHeight_int ()
{