Pie*_*aud 50 c# generics struct constraints class
我想区分以下情况:
int)int?)string) - 可选地,我不关心这是否映射到上面的(1)或(2)我已经提出了以下代码,它适用于案例(1)和(2):
static void Foo<T>(T a) where T : struct { } // 1
static void Foo<T>(T? a) where T : struct { } // 2
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试像这样检测case(3),它就不会编译:
static void Foo<T>(T a) where T : class { } // 3
Run Code Online (Sandbox Code Playgroud)
错误消息是类型'X'已经定义了一个名为'Foo'的成员,它具有相同的参数类型.好吧,不知何故,我无法在where T : struct和之间产生影响where T : class.
如果我删除第三个函数(3),以下代码也不会编译:
int x = 1;
int? y = 2;
string z = "a";
Foo (x); // OK, calls (1)
Foo (y); // OK, calls (2)
Foo (z); // error: the type 'string' must be a non-nullable value type ...
Run Code Online (Sandbox Code Playgroud)
我如何Foo(z)编译,将其映射到上述函数之一(或第三个具有另一个约束,我没有想到)?
Alc*_*aro 51
约束不是签名的一部分,但参数是.并且在重载决策期间强制执行参数约束.
所以我们把约束放在一个参数中.这很难看,但它确实有效.
class RequireStruct<T> where T : struct { }
class RequireClass<T> where T : class { }
static void Foo<T>(T a, RequireStruct<T> ignore = null) where T : struct { } // 1
static void Foo<T>(T? a) where T : struct { } // 2
static void Foo<T>(T a, RequireClass<T> ignore = null) where T : class { } // 3
Run Code Online (Sandbox Code Playgroud)
(迟到六年比从未好过?)
ang*_*son 21
不幸的是,您无法仅根据约束来区分要调用的方法类型.
因此,您需要在不同的类中定义方法或使用不同的名称来定义方法.
Luk*_*keH 10
除了你对Marnix答案的评论之外,你可以通过一些反思来达到你想要的效果.
在下面的示例中,无约束Foo<T>方法使用反射来调用对相应约束方法的调用 - FooWithStruct<T>或者FooWithClass<T>.出于性能原因,我们将创建并缓存强类型委托,而不是每次Foo<T>调用方法时使用纯反射.
int x = 42;
MyClass.Foo(x); // displays "Non-Nullable Struct"
int? y = 123;
MyClass.Foo(y); // displays "Nullable Struct"
string z = "Test";
MyClass.Foo(z); // displays "Class"
// ...
public static class MyClass
{
public static void Foo<T>(T? a) where T : struct
{
Console.WriteLine("Nullable Struct");
}
public static void Foo<T>(T a)
{
Type t = typeof(T);
Delegate action;
if (!FooDelegateCache.TryGetValue(t, out action))
{
MethodInfo mi = t.IsValueType ? FooWithStructInfo : FooWithClassInfo;
action = Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(t));
FooDelegateCache.Add(t, action);
}
((Action<T>)action)(a);
}
private static void FooWithStruct<T>(T a) where T : struct
{
Console.WriteLine("Non-Nullable Struct");
}
private static void FooWithClass<T>(T a) where T : class
{
Console.WriteLine("Class");
}
private static readonly MethodInfo FooWithStructInfo = typeof(MyClass).GetMethod("FooWithStruct", BindingFlags.NonPublic | BindingFlags.Static);
private static readonly MethodInfo FooWithClassInfo = typeof(MyClass).GetMethod("FooWithClass", BindingFlags.NonPublic | BindingFlags.Static);
private static readonly Dictionary<Type, Delegate> FooDelegateCache = new Dictionary<Type, Delegate>();
}
Run Code Online (Sandbox Code Playgroud)
(请注意,此示例不是线程安全的.如果您需要线程安全,那么您需要使用某种锁定围绕对缓存字典的所有访问,或者 - 如果您能够以.NET4为目标 - 使用ConcurrentDictionary<K,V>代替.)
删除第一个方法上的结构约束.如果需要区分值类型和类,可以使用参数类型来实现.
static void Foo( T? a ) where T : struct
{
// nullable stuff here
}
static void Foo( T a )
{
if( a is ValueType )
{
// ValueType stuff here
}
else
{
// class stuff
}
}
Run Code Online (Sandbox Code Playgroud)