Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NativeAOT and trimming support #537

Open
tompipe opened this issue Sep 17, 2024 · 0 comments
Open

NativeAOT and trimming support #537

tompipe opened this issue Sep 17, 2024 · 0 comments

Comments

@tompipe
Copy link

tompipe commented Sep 17, 2024

Firstly, let me open with my thanks for this library, I've only recently discovered it, but wish I'd found it earlier! 😄

I've had a minor issue in the project I'm working on, which is being compiled for native AOT. The following warning is displayed in VS:

Assembly 'Ardalis.SmartEnum' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries

And it didn't work as expected, due to my smart enum not being able to obtain values using the TryFromValue method.

I had a quick look at the source, and I suspected this was due to the use of reflection:

private static TEnum[] GetAllOptions()
{
Type baseType = typeof(TEnum);
return Assembly.GetAssembly(baseType)
.GetTypes()
.Where(t => baseType.IsAssignableFrom(t))
.SelectMany(t => t.GetFieldsOfType<TEnum>())
.OrderBy(t => t.Name)
.ToArray();
}

public static List<TFieldType> GetFieldsOfType<TFieldType>(this Type type)
{
return type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(p => type.IsAssignableFrom(p.FieldType))
.Select(pi => (TFieldType)pi.GetValue(null))
.ToList();
}

I was successfully able to hack around it, by adding the following to my enum, providing the hints to the IL to prevent it optimizing away the info needed to perform reflection.

[RequiresUnreferencedCode("Calls System.Reflection.Assembly.GetTypes()")]    
public sealed class MySmartEnum : SmartEnum<MySmartEnum, Guid>
{
	[DynamicDependency(DynamicallyAccessedMemberTypes.PublicFields, typeof(MySmartEnum))]
	public new static MySmartEnum FromName(string name, bool ignoreCase = false)
	{
	    return SmartEnum<MySmartEnum, Guid>.FromName(name, ignoreCase);
	}

	[DynamicDependency(DynamicallyAccessedMemberTypes.PublicFields, typeof(MySmartEnum))]
	public new static MySmartEnum FromValue(Guid value)
	{
	    return SmartEnum<MySmartEnum, Guid>.FromValue(value);
	}

	[DynamicDependency(DynamicallyAccessedMemberTypes.PublicFields, typeof(MySmartEnum))]
	public new static bool TryFromValue(Guid value, out MySmartEnum result)
	{
	    return SmartEnum<MySmartEnum, Guid>.TryFromValue(value, out result);
	}

	[DynamicDependency(DynamicallyAccessedMemberTypes.PublicFields, typeof(MySmartEnum))]
	public new static bool TryFromName(string name, out MySmartEnum result)
	{
	    return SmartEnum<MySmartEnum, Guid>.TryFromName(name, out result);
	}
}

Thought It would be beneficial to set these options in the source if possible, so the warnings are prevented, or at least open an issue for others to reference if they're in a similar situation.

Perhaps its also worth giving some consideration to the feasiblity of whether the use of reflection could be avoided entirely/optionally.

Could derived classes provide their own implementation of GetAllOptions, or perhaps theres another approach of handling the 'discoverability' of available options?

Could it be as simple as being 'registered' into the _enumOptions collection when being constructed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant