Skip to content

Instantly share code, notes, and snippets.

@akeit0
Last active February 27, 2025 14:28
Show Gist options
  • Select an option

  • Save akeit0/3be417649abde101678a874af3760659 to your computer and use it in GitHub Desktop.

Select an option

Save akeit0/3be417649abde101678a874af3760659 to your computer and use it in GitHub Desktop.
What IL can do for generics constraints.
using System.Numerics;
using System.Runtime.CompilerServices;
using InlineIL;
//Not IDisposable
TestClass.DisposeTest(1);
//TestClass
Console.WriteLine(TestClass.Self(new TestClass()));
//Dispose
TestClass.DisposeUnconstrained(new TestClass());
//True
Console.WriteLine(TestClass.EqualsUnConstrained(1, 1));
//3
Console.WriteLine(TestClass.AddConstrained(1, 2));
//Unhandled exception. System.Security.VerificationException: Method TestClass.Add: type argument 'T' violates the constraint of type parameter 'T'.
Console.WriteLine(TestClass.AddUnconstrained(1, 2));
interface IGetSelf<T>
{
static abstract T GetSelf(T a);
}
class TestClass : IDisposable, IGetSelf<TestClass>
{
public void Dispose()
{
Console.WriteLine("Dispose");
}
public static TestClass GetSelf(TestClass a) => a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DisposeTest<T>(T a)
{
if (typeof(T).IsAssignableTo(typeof(IDisposable)))
{
DisposeUnconstrained(a);
}
else
{
Console.WriteLine("Not IDisposable");
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DisposeUnconstrained<T>(T a)
{
IL.Emit.Ldarga_S(nameof(a));
IL.Emit.Constrained<T>();
IL.Emit.Callvirt(new MethodRef(new TypeRef(typeof(IDisposable)), nameof(Dispose)));
;
}
public static bool EqualsUnConstrained<T>(T a, T b)// where T : IEquatable<T>
{
IL.Emit.Ldarga_S(nameof(a));
IL.Emit.Ldarg(nameof(b));
IL.Emit.Constrained<T>();
IL.Emit.Callvirt(new MethodRef(new TypeRef(typeof(IEquatable<T>)), nameof(Equals)));
return IL.Return<bool>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T AddConstrained<T>(T a, T b) where T : INumber<T>
{
IL.Emit.Ldarg(nameof(a));
IL.Emit.Ldarg(nameof(b));
IL.Emit.Call(new MethodRef(new TypeRef(typeof(TestClass)), nameof(Add)).MakeGenericMethod(typeof(T)));
return IL.Return<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T AddUnconstrained<T>(T a, T b)//where T : INumber<T>
{
IL.Emit.Ldarg(nameof(a));
IL.Emit.Ldarg(nameof(b));
IL.Emit.Constrained<T>();
IL.Emit.Call(new MethodRef(new TypeRef(typeof(IAdditionOperators<,,>).MakeGenericType(typeof(T),typeof(T),typeof(T))),"op_Addition"));
return IL.Return<T>();
}
static T Add<T>(T a, T b) where T : INumber<T>
{
return a + b;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Self<T>(T a)//where T : INumber<T>
{
IL.Emit.Ldarg(nameof(a));
IL.Emit.Constrained<T>();
IL.Emit.Call(new MethodRef(new TypeRef(typeof(IGetSelf<T>)),"GetSelf"));
return IL.Return<T>();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment