Skip to content

Instantly share code, notes, and snippets.

@ufcpp
Last active April 18, 2025 01:35
Show Gist options
  • Save ufcpp/2d042620f5349b89afceb66b8d3eae51 to your computer and use it in GitHub Desktop.
Save ufcpp/2d042620f5349b89afceb66b8d3eae51 to your computer and use it in GitHub Desktop.
OverloadResolutionPriority を使った制約違いオーバーロード
using System.Runtime.CompilerServices;
Ex.M<C1>(); // where class
Ex.M<S1>(); // where struct
Ex.M<C2>(); // where class, I
Ex.M<S2>(); // where struct, I
Ex.M<I>(); // これは class, I に行く。インターフェイスは参照型なので。
static void M1<T>() => Ex.M<T>(); // none
static void M2<T>() where T : I => Ex.M<T>(); // where I
// 型引数で渡す予定の型。
interface I;
class C1;
struct S1;
class C2 : I;
struct S2 : I;
// 制約違いオーバーロード。
static class Ex
{
[OverloadResolutionPriority(-2)]
public static void M<T>() => Console.WriteLine("none");
[OverloadResolutionPriority(-1)]
public static void M<T>(Tag<Struct> _ = default) where T : struct => Console.WriteLine("struct");
[OverloadResolutionPriority(-1)]
public static void M<T>(Tag<Class> _ = default) where T : class => Console.WriteLine("class");
[OverloadResolutionPriority(-1)]
public static void M<T>(Tag<I> _ = default) where T : I => Console.WriteLine("I");
[OverloadResolutionPriority(0)]
public static void M<T>(Tag<Struct, I> _ = default) where T : struct, I => Console.WriteLine("struct : I");
[OverloadResolutionPriority(0)]
public static void M<T>(Tag<Class, I> _ = default) where T : class, I => Console.WriteLine("class : I");
}
// オーバーロードを増やすためのダミー型。
struct Struct;
struct Class;
struct Tag<T1>;
struct Tag<T1, T2>;
using System.Runtime.CompilerServices;
Ex.M<O>(); // class
Ex.M<A>(); // class, IA
Ex.M<B>(); // class, IB
Ex.M<AB>(); // class, IA, IB
Ex.M<Os>(); // struct
Ex.M<As>(); // struct, IA
Ex.M<Bs>(); // struct, IB
Ex.M<ABs>(); // struct, IA, IB
// インターフェイスは参照型なので:
Ex.M<IA>(); // これは class, IA に行く。
Ex.M<IB>(); // これは class, IB に行く。
Unconstrained.O<O>(); // none
Unconstrained.A<A>(); // IA
Unconstrained.B<B>(); // IB
Unconstrained.AB<AB>(); // IA, IB
class Unconstrained
{
public static void O<T>() => Ex.M<T>();
public static void A<T>() where T : IA => Ex.M<T>();
public static void B<T>() where T : IB => Ex.M<T>();
public static void AB<T>() where T : IA, IB => Ex.M<T>();
}
// 型引数で渡す予定の型。
interface IA;
interface IB;
class O;
class A : IA;
class B : IB;
class AB : IA, IB;
struct Os;
struct As : IA;
struct Bs : IB;
struct ABs : IA, IB;
// 制約違いオーバーロード。
// OverloadResolutionPriority の値は「制約の数」にしとく。
static class Ex
{
public static void M<T>() => Console.WriteLine("none");
[OverloadResolutionPriority(1)]
public static void M<T>(Tag<Struct> _ = default) where T : struct => Console.WriteLine("struct");
[OverloadResolutionPriority(1)]
public static void M<T>(Tag<Class> _ = default) where T : class => Console.WriteLine("class");
[OverloadResolutionPriority(1)]
public static void M<T>(Tag<IA> _ = default) where T : IA => Console.WriteLine("IA");
[OverloadResolutionPriority(1)]
public static void M<T>(Tag<IB> _ = default) where T : IB => Console.WriteLine("IB");
[OverloadResolutionPriority(2)]
public static void M<T>(Tag<Struct, IA> _ = default) where T : struct, IA => Console.WriteLine("struct, IA");
[OverloadResolutionPriority(2)]
public static void M<T>(Tag<Class, IA> _ = default) where T : class, IA => Console.WriteLine("class, IA");
[OverloadResolutionPriority(2)]
public static void M<T>(Tag<Struct, IB> _ = default) where T : struct, IB => Console.WriteLine("struct, IB");
[OverloadResolutionPriority(2)]
public static void M<T>(Tag<Class, IB> _ = default) where T : class, IB => Console.WriteLine("class, IB");
[OverloadResolutionPriority(2)]
public static void M<T>(Tag<IA, IB> _ = default) where T : IA, IB => Console.WriteLine("IA, IB");
[OverloadResolutionPriority(3)]
public static void M<T>(Tag<Struct, IA, IB> _ = default) where T : struct, IA, IB => Console.WriteLine("struct, IA, IB");
[OverloadResolutionPriority(3)]
public static void M<T>(Tag<Class, IA, IB> _ = default) where T : class, IA, IB => Console.WriteLine("class, IA, IB");
}
// オーバーロードを増やすためのダミー型。
struct Struct;
struct Class;
struct Tag<T1>;
struct Tag<T1, T2>;
struct Tag<T1, T2, T3>;
using System.Runtime.CompilerServices;
Ex.M<O>();
Ex.M<A>();
Ex.M<B>();
Ex.M<AB>();
// 型引数で渡す予定の型。
interface IA;
interface IB;
class O;
class A : IA;
class B : IB;
class AB : IA, IB;
// 制約違いオーバーロード。
static class Ex
{
[OverloadResolutionPriority(-2)]
public static void M<T>() => Console.WriteLine("O");
[OverloadResolutionPriority(-1)]
public static void M<T>(Tag<IA> _ = default) where T : IA => Console.WriteLine("A");
[OverloadResolutionPriority(-1)]
public static void M<T>(Tag<IB> _ = default) where T : IB => Console.WriteLine("B");
[OverloadResolutionPriority(0)]
public static void M<T>(Tag<IA, IB> _ = default) where T : IA, IB => Console.WriteLine("A, B");
}
// オーバーロードを増やすためのダミー型。
struct Tag<T1>;
struct Tag<T1, T2>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment