-
Notifications
You must be signed in to change notification settings - Fork 1.9k
XAML compilation (XamlC) fails with generic types #1497
Description
Description
There's a bug in the Xamarin XAML compilation code that can be observed when referencing from XAML code a generic type having multiple type parameters and a concrete type is specified for one of them.
I think that the problem will be easier to understand with the example described below.
Steps to Reproduce
-
Create a new cross-platform (Xamarin.Forms) project from VisualStudio. See the screenshot below to check which settings where used. You can also download the attached project.
Note: the bug appears when compiling xaml code contained in either a .NET Standard Library or PCL project -> You can choose whatever platform you like (Android, iOS or UWP), it doesn't matter. -
Add the BaseValidationBehavior class to the root of the project.
Note: the BaseValidationBehavior contains code (not shown here) common to all behaviors that validates user input:
using Xamarin.Forms;
namespace XamBugGenerics
{
internal abstract class BaseValidationBehavior<TBindable, TModel> : Behavior<TBindable> where TBindable : BindableObject
{
}
}
Here both 'TBindable' and 'TModel' are type parameters.
- Add the EntryValidationBehavior class to the root of the project.
This class contains code (not shown here) to validate 'Entry' views content.
using Xamarin.Forms;
namespace XamBugGenerics
{
internal sealed class EntryValidationBehavior<TModel> : BaseValidationBehavior<Entry, TModel>
{
}
}
Note: 'TModel' is a type parameter but 'Entry' is a concrete type. Mixing type parameters and concrete types is what triggers the XAML compilation bug.
- Add the XAML compilation attribute shown below to the MainPage.xaml.cs:
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace XamBugGenerics
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
}
- Add an 'Entry' to the MainPage.xaml as shown below:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamBugGenerics"
x:Class="XamBugGenerics.MainPage">
<Entry VerticalOptions="Center"
HorizontalOptions="Center">
<Entry.Behaviors>
<local:EntryValidationBehavior x:TypeArguments="Entry"/>
</Entry.Behaviors>
</Entry>
</ContentPage>
Note: normally in a real project we should pass a model type as 'TypeArgument', but to reveal the bug any type can be used.
Expected Behavior
The XamlCTask is able to correctly compile the XAML code without raising an exception.
Actually the same code runs without issues when XAML compilation is deactivated.
Actual Behavior
By changing the logging verbosity of the XamlCTask in the Xamarin.Forms.targets file, you can observe this error in the build output window when building the project:
1>Target XamlC:
1> Using "XamlCTask" task from assembly "C:\Users\[removed]\.nuget\packages\xamarin.forms\2.5.0.121934\build\netstandard1.0\Xamarin.Forms.Build.Tasks.dll".
1> Task "XamlCTask"
1> Compiling Xaml
1>
1> Assembly: obj\Debug\netstandard2.0\XamBugGenerics.dll
1> ReferencePath: C:\Program Files\dotnet\sdk\NuGetFallbackFolder\netstandard.library\2.0.0\build\netstandard2.0\ref\Microsoft.Win32.Primitives.dll;
1> [multiple lines removed]
1> DebugSymbols:"True"
1> DebugType:"portable"
1> Adding searchpath C:\Program Files\dotnet\sdk\NuGetFallbackFolder\netstandard.library\2.0.0\build\netstandard2.0\ref
1> Adding searchpath C:\Users\[removed]\.nuget\packages\xamarin.forms\2.5.0.121934\lib\netstandard1.0
1> [multiple lines removed]
1> Module: XamBugGenerics.dll
1> Resource: XamBugGenerics.App.xaml... Has XamlCompilationAttribute set to Skip and not Compile... skipped
1> Resource: XamBugGenerics.MainPage.xaml...
1> Creating empty MainPage.__InitComponentRuntime ...done.
1> Copying body of InitializeComponent to __InitComponentRuntime ...done.
1> Parsing Xaml... done.
1> Replacing MainPage.InitializeComponent ()... failed.
1> D:\Dev\Xamarin\XamBugGenerics\XamBugGenerics\XamBugGenerics\MainPage.xaml : error : Object reference not set to an instance of an object.
1> at Xamarin.Forms.Build.Tasks.TypeReferenceExtensions.ResolveGenericParameters(TypeReference self, TypeReference declaringTypeReference)
1> at Xamarin.Forms.Build.Tasks.TypeReferenceExtensions.InheritsFromOrImplements(TypeReference typeRef, TypeReference baseClass)
1> at Xamarin.Forms.Build.Tasks.SetNamescopesAndRegisterNamesVisitor.Visit(ElementNode node, INode parentNode)
1> at Xamarin.Forms.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
1> at Xamarin.Forms.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
1> at Xamarin.Forms.Xaml.RootNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
1> at Xamarin.Forms.Build.Tasks.XamlCTask.TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime, ILRootNode rootnode, String resourceId, Exception& exception)
1> Changing the module MVID...done.
1>
1> Writing the assembly... done.
1> Done executing task "XamlCTask" -- FAILED.
1>Done building target "XamlC" in project "XamBugGenerics.csproj" -- FAILED.
Because of this bug I had to deactivate XAML compilation on every page where I'm validating user input.
Basic Information
- Version with issue: Xamarin.Forms 2.5.0.121934
- IDE: Visual Studio Enterprise 2017 v15.5.2
- Platform Target Frameworks: not relevant. The bug comes from either a .NET standard library or PCL project.
- Nuget Packages: NETStandard.Library 2.0.0 and Xamarin.Forms v2.5.0.121934
Screenshots
Xamarin Forms project configuration
Xamarin Forms project structure