AOT issue for Xamarin/MAUI
Not sure if this can be fixed in Mapster but I'm getting this crash when running a MAUI app on a physical iPhone (running in a simulator is fine). Mapster 7.4.0 and .NET 7.
Attempting to JIT compile method '(wrapper delegate-invoke) int <Module>:invoke_callvirt_int_List1<PromoItemDistributionDTO/DistributionDetail> (System.Collections.Generic.List1<METIS.DTOs.PromoItemDTOs.PromoItemDistributionDTO/DistributionDetail>)' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.
Calling Adapt on a simple class is fine. The crash occurs when the class contains a subclass. Example:
//Convert list of PromoItemDTOs to PromoItems
SelectedDistributionDetail = new PromoItemDistribution(promoDistributionDto.Result);
public partial class PromoItemDistributionDTO
{
public Guid PromoItemDistributionId { get; set; } // PromoItemDistributionId (Primary key)
public int ReceiptNo { get; set; } // ReceiptNo
public Guid ContactId { get; set; } // ContactId
public int PromoItemDistributionTypeId { get; set; } // PromoItemDistributionTypeId
...
public List<DistributionDetail>? DistributionDetails { get; set; }
public partial class DistributionDetail
{
public long PromoItemDistributionDetailId { get; set; } // PromoItemDistributionDetailId (Primary key)
public Guid PromoItemVariationId { get; set; } // PromoItemVariationId
public string ItemName { get; set; } // ItemName (length: 255)
...
}
}
public class PromoItemDistribution : PromoItemDistributionDTO, INotifyPropertyChanged
{
public new List<ExtendedDistributionDetail>? DistributionDetails { get; set; }
public PromoItemDistribution()
{
DistributionDetails = new List<ExtendedDistributionDetail>();
}
public PromoItemDistribution(PromoItemDistributionDTO promoItemDistributionDTO)
{
promoItemDistributionDTO.Adapt(this);
DistributionDetails = promoItemDistributionDTO.DistributionDetails?
.Select(detail => detail.Adapt<ExtendedDistributionDetail>())
.ToList();
}
public partial class DistributionDetail
{
}
public string DistributionType
{
get
{
if (PromoItemDistributionTypeId == 1)
return "Pickup";
else
{
if (string.IsNullOrEmpty(DeliveredBy))
return "Delivery";
else
return "Delivery (" + DeliveredBy + ")";
}
}
}
public string CreatedOnFormatted => CreatedOn.ToString().FormatToDateTimeString("ddMMMyyyy").ToUpper();
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ExtendedDistributionDetail : PromoItemDistributionDTO.DistributionDetail, INotifyPropertyChanged
{
public string CreatedOnFormatted { get; set; }
public string ItemDescriptionShort => QtyDistributed.ToString() + " x " + ClothesSize + " - " + ItemDetail;
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Hello @NeilN1
On real hardware, you can adapt Collections. In a simple case?
var result = DistributionDetails.Adapt<List<ExtendedDistributionDetail>>()
if Yes, Then this is the reason for the error in this code
> public PromoItemDistribution(PromoItemDistributionDTO promoItemDistributionDTO)
>
{
> promoItemDistributionDTO.Adapt(this);
> DistributionDetails = promoItemDistributionDTO.DistributionDetails? // this transform
> .Select(detail => detail.Adapt<ExtendedDistributionDetail>())
> .ToList();
> }
On real hardware I can adapt simple classes with a property defined as a subclass. However, a crash occurs when that property is defined as a List.
This works:
public partial class TestClass1DTO
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Phone? PrimaryPhone { get; set; }
public partial class Phone
{
public string PhoneType { get; set; }
public string PhoneNumber { get; set; }
}
}
public partial class TestClass : TestClass1DTO, INotifyPropertyChanged
{
public TestClass(TestClass1DTO testClass1DTO)
{
testClass1DTO.Adapt(this);
}
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
List<TestClass1DTO> testClass1DTOs = new List<TestClass1DTO>();
testClass1DTOs.Add(new TestClass1DTO()
{
FirstName = "John",
LastName = "Doe",
PrimaryPhone = new TestClass1DTO.Phone()
{
PhoneType = "Home",
PhoneNumber = "123-456-7890"
}
});
testClass1DTOs.Add(new TestClass1DTO()
{
FirstName = "Jane",
LastName = "Smint",
PrimaryPhone = new TestClass1DTO.Phone()
{
PhoneType = "Home",
PhoneNumber = "111-456-7890"
}
});
List<TestClass> testClasses = testClass1DTOs.Select(x => new TestClass(x)).ToList();
This does not:
public partial class TestClass1DTO
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Phone>? PhoneNumbers { get; set; }
public partial class Phone
{
public string PhoneType { get; set; }
public string PhoneNumber { get; set; }
}
}
public partial class TestClass : TestClass1DTO, INotifyPropertyChanged
{
public TestClass(TestClass1DTO testClass1DTO)
{
testClass1DTO.Adapt(this);
}
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
List<TestClass1DTO> testClass1DTOs = new List<TestClass1DTO>();
testClass1DTOs.Add(new TestClass1DTO()
{
FirstName = "John",
LastName = "Doe",
PhoneNumbers = new List<TestClass1DTO.Phone>()
{
new TestClass1DTO.Phone()
{
PhoneType = "Home",
PhoneNumber = "123-456-7890"
},
new TestClass1DTO.Phone()
{
PhoneType = "Work",
PhoneNumber = "987-654-3210"
}
}
});
testClass1DTOs.Add(new TestClass1DTO()
{
FirstName = "Jane",
LastName = "Smint",
PhoneNumbers = new List<TestClass1DTO.Phone>()
{
new TestClass1DTO.Phone()
{
PhoneType = "Home",
PhoneNumber = "111-456-7890"
},
new TestClass1DTO.Phone()
{
PhoneType = "Work",
PhoneNumber = "222-654-3210"
}
}
});
List<TestClass> testClasses = testClass1DTOs.Select(x => new TestClass(x)).ToList();
This seems to be due to the inability to dynamically create a specific implementation of a generic class in AOT, including generic collections.
Yes, the link in my first post referred to that. Is this something that can be fixed in Mapster or should we avoid using it in iOS apps for classes that have List properties?