我有一个方法的两个实现,一个用于值类型,另一个用于引用类型:
public static Result<T> ImplRef(T arg) where T : class {...}
public static Result<T> ImplVal(T arg) where T : struct {...}
我想写一个方法来调用正确的实现,就像这个
public static Result<T> Generic(T arg) {
if (typeOf(T).IsValueType)
return ImplVal(arg);
else
return ImplRef(arg);
}
显然,上面的实现没有编译。如何以最少的反射来做到这一点?
答案 0 :(得分:4)
泛型的想法通常是用你给出的任何输入做同样的逻辑,虽然显然你需要实用。就个人而言,我可能会使用两种不同的方法,而不是将它们暴力强加到同一种方法中,但这样就很难通过只知道T
的通用方法进行调用。虽然: class
方法可能有效,但无法满足静态代码中的: struct
/ MakeGenericMethod
,但速度会慢一些。
// slow; use with caution
public static Result<T> Generic<T>(T arg) {
if (typeof(T).IsValueType)
return (Result<T>)typeof(Program).GetMethod("ImplVal")
.MakeGenericMethod(typeof(T))
.Invoke(null, new object[] {arg});
else
return (Result<T>)typeof(Program).GetMethod("ImplRef")
.MakeGenericMethod(typeof(T))
.Invoke(null, new object[] { arg });
}
(用托管方法的类型替换typeof(Program)
)
备选方案(如Jon所说)是将(类型化)委托缓存到方法中:
public static Result<T> Generic<T>(T arg) {
return Cache<T>.CachedDelegate(arg);
}
internal static class Cache<T>
{
public static readonly Func<T, Result<T>> CachedDelegate;
static Cache()
{
MethodInfo method;
if (typeof(T).IsValueType)
method = typeof(Program).GetMethod("ImplVal")
.MakeGenericMethod(typeof(T));
else
method = typeof(Program).GetMethod("ImplRef")
.MakeGenericMethod(typeof(T));
CachedDelegate = (Func<T, Result<T>>)Delegate.CreateDelegate(
typeof(Func<T, Result<T>>), method);
}
}
更多工作,但会很快。静态构造函数(或者你可以使用property / null检查)确保我们只做一次艰苦的工作。
答案 1 :(得分:2)
您实际上使用 ImplRef
和ImplVal
中的约束吗?如果不是(即如果它只是这样你可以表现不同)你可以删除约束,使方法保密,并从Generic
恰当地调用它们 - 或者可能有:
public static Result<T> ImplRef(T arg) where T : class
{
return ImplRefImpl(arg);
}
private static Result<T> ImplRefImpl(T arg)
{
// Real code
}
public static Result<T> ImplVal(T arg) where T : struct
{
return ImplValImpl(arg);
}
private static Result<T> ImplValImpl(T arg)
{
// Real code
}
顺便说一下,如果T
是可以为空的类型,您应该考虑该怎么做 - 它实际上并不满足class
或struct
约束。
顺便说一下,另一种测试T是值类型的方法(可能更有效 - 不确定)是:
if (default(T) == null)
请注意,与IsValueType的测试不同,这将为可空类型“传递”,因此行为不相同。
答案 2 :(得分:0)
是否有理由不能使用两个单独的实现(可能都使用第三个常见实现)?
使用typeof
表示您正在执行RTTI,这会让您的应用变得更慢。使用编译器(通过使用类和结构的单独实现)会更快,因为所有关于类型的决定都将由编译器在JIT编译期间处理。
答案 3 :(得分:-1)
为什么不让编译器选择?
public static Result<T> ToResult<T>(this T arg) where T: class
{ return new ImplRef(arg); }
public static Result<T> ToResult<T>(this T arg) where T: struct
{ return new ImplVal(arg)
用作:
"hi".ToResult();
3.ToResult();