Hello! I have a base generic class and it's two heirs. Base class has a function, which I bind to buttons as a command for both of my heirs. When I click on the button which is bound to the first heir everything is fine. When I click on the button which is bound to the second heir I get InvalidCastException. I am not sure if that's a bug or if I am doing something very wrong. I hope for your help, cheers!
To Reproduce
I've created a fresh project to reproduce this behaviour. Here is the code:
Models/Models.cs
internal class BaseModel<TData, TSelf>(Func<TData> print)
where TSelf : BaseModel<TData, TSelf>
{
public void Print()
{
Console.WriteLine(_print());
}
private readonly Func<TData> _print = print;
}
internal class ModelA(Func<string> print) : BaseModel<string, ModelA>(print)
{
}
internal class ModelB(Func<byte> print) : BaseModel<byte, ModelB>(print)
{
}
ViewModels/MainWindowViewModel.cs
internal class MainWindowViewModel : ViewModelBase
{
public ModelA ModelA => new(() => "apple");
public ModelB ModelB => new(() => 123);
}
Press button "Print A" -> see message "apple".
Press button "Print B" -> see message "123".
Actual behaviour
Press button "Print A" -> see message "apple".
Press button "Print B" -> get exception:
System.InvalidCastException
HResult=0x80004002
Message=Unable to cast object of type 'TestAvaloniaBug.Models.ModelB' to type 'TestAvaloniaBug.Models.BaseModel`2[System.String,TestAvaloniaBug.Models.ModelA]'.
Source=TestAvaloniaBug
StackTrace:
at CompiledAvaloniaXaml.XamlIlTrampolines.TestAvaloniaBug:TestAvaloniaBug.Models.BaseModel`2+Print_0!CommandExecuteTrampoline(Object , Object )
at Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.CommandAccessorPlugin.CommandAccessor.Command.Execute(Object parameter)
at Avalonia.Controls.Button.OnClick()
at Avalonia.Controls.Button.OnPointerReleased(PointerReleasedEventArgs e)
at Avalonia.Input.InputElement.<>c.<.cctor>b__32_9(InputElement x, PointerReleasedEventArgs e)
at Avalonia.Reactive.LightweightObservableBase`1.PublishNext(T value)
at Avalonia.Interactivity.EventRoute.RaiseEventImpl(RoutedEventArgs e)
at Avalonia.Interactivity.Interactive.RaiseEvent(RoutedEventArgs e)
at Avalonia.Input.MouseDevice.MouseUp(IMouseDevice device, UInt64 timestamp, IInputRoot root, Point p, PointerPointProperties props, KeyModifiers inputModifiers, IInputElement hitTest)
at Avalonia.Input.MouseDevice.ProcessRawEvent(RawPointerEventArgs e)
at Avalonia.Controls.TopLevel.HandleInput(RawInputEventArgs e)
at Avalonia.Win32.WindowImpl.AppWndProc(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam)
at Avalonia.Win32.WindowImpl.WndProc(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam)
at Avalonia.Win32.Interop.UnmanagedMethods.DispatchMessage(MSG& lpmsg)
at Avalonia.Win32.Win32DispatcherImpl.RunLoop(CancellationToken cancellationToken)
at Avalonia.Threading.DispatcherFrame.Run(IControlledDispatcherImpl impl)
at Avalonia.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancellationToken)
at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args)
at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime(AppBuilder builder, String[] args, ShutdownMode shutdownMode)
at TestAvaloniaBug.Program.Main(String[] args) in C:\...\TestAvaloniaBug\Program.cs:line 13
Environment
OS: MS Windows 11 Pro 10.0.22621 x64
.NET SDK: 8.0.100
Avalonia: 11.0.5
P.S.
I have a temporary solution to the issue: everything is fine when I override the function in any of the heirs. For instance:
internal class ModelA(Func<string> print) : BaseModel<string, ModelA>(print)
{
public new void Print() => base.Print();
}
Update 2023-12-06
CompiledAvaloniaXaml
using Avalonia.Utilities;
using System.Globalization;
using System.Runtime.InteropServices;
using TestAvaloniaBug.Models;
namespace CompiledAvaloniaXaml
{
internal class XamlIlTrampolines
{
public static void TestAvaloniaBug:TestAvaloniaBug.Models.BaseModel`2+Print_0!CommandExecuteTrampoline(
[In] object obj0,
[In] object obj1)
{
((BaseModel<string, ModelA>) obj0).Print();
}
}
}
Describe the bug
Hello! I have a base generic class and it's two heirs. Base class has a function, which I bind to buttons as a command for both of my heirs. When I click on the button which is bound to the first heir everything is fine. When I click on the button which is bound to the second heir I get InvalidCastException. I am not sure if that's a bug or if I am doing something very wrong. I hope for your help, cheers!
To Reproduce
I've created a fresh project to reproduce this behaviour. Here is the code:
Models/Models.cs
ViewModels/MainWindowViewModel.cs
Views/MainWindow.axaml
Expected behaviour
Press button "Print A" -> see message "apple". Press button "Print B" -> see message "123".
Actual behaviour
Press button "Print A" -> see message "apple". Press button "Print B" -> get exception:
Environment
P.S.
I have a temporary solution to the issue: everything is fine when I override the function in any of the heirs. For instance:
Update 2023-12-06
CompiledAvaloniaXaml