将不受限制的泛型类型参数传递给受限制的方法

3

我有两种方法:

public TValueType? DoStuffWithValueType<TValueType>(int x, int y) 
   where TValueType: struct {}

public TRefType DoStuffWithRefType<TRefType>(int x, int y) 
   where TRefType: class {} 

我该如何在新的第三个方法中包装它们?

由于在调用 DoStuffWithValueType 时无法让编译器相信 T 实际上是一个结构体,因此以下内容无法编译:

public T DoStuff<T>(int x, int y) {

   if(typeof(T).IsValueType)
   {
      return DoStuffWithValueType<T>(x, y);
   }

   return DoStuffWithRefType<T>(x, y);
}

我已经尝试过重载DoStuff,但是由于泛型约束不是方法签名的一部分,所以这次尝试失败了。
我还试图去掉这些约束,但是无法做到。

有什么想法吗?谢谢!


1
提前警告:类型是值类型并不一定意味着它是struct约束的有效泛型类型参数。可空值类型不能与classstruct约束一起使用。 - user743382
2个回答

2
基本上你不能这样做 - 你需要使用反射调用相关方法,这很丑陋。
当然,你可以通过动态类型来实现,这会将反射隐藏起来。
public T DoStuff<T>(int x, int y) {
   dynamic d = this;
   if(typeof(T).IsValueType)
   {
       return d.DoStuffWithValueType<T>(x, y);
   }    
   return d.DoStuffWithRefType<T>(x, y);
}

你可能认为这比使用反射手动操作更加简洁 - 或者不这样认为 :)
据我所知,没有办法让编译器“信任”一个类型参数,除非它本来就应该这样做。

谢谢!从没想过像您这样的名人会回答我的问题 ;) - keydon

2
除了Jon Skeet使用动态类型(dynamic)外,我能想到最简洁的方法是通过助手类调用方法,从而最小化所需的反射,并使尽可能多的代码得到编译器验证。
abstract class DoStuffHelper<T> {
    public abstract T DoStuff(int x, int y);
}

class DoStuffWithValueTypeHelper<T> : DoStuffHelper<T> where T : struct {
    public override T DoStuff(int x, int y) {
        return DoStuffWithValueType<T>(x, y);
    }
}

class DoStuffWithRefTypeHelper<T> : DoStuffHelper<T> where T : class {
    public override T DoStuff(int x, int y) {
        return DoStuffWithRefType<T>(x, y);
    }
}

public T DoStuff<T>(int x, int y) {
   DoStuffHelper<T> helper;
   Type helperType;

   if(typeof(T).IsValueType)
       helperType = typeof(DoStuffWithValueTypeHelper<>);
   else
       helperType = typeof(DoStuffWithRefTypeHelper<>);

   helperType = helperType.MakeGenericType(typeof(T));
   helper = (DoStuffHelper<T>)Activator.CreateInstance(helperType);

   return helper.DoStuff(x, y);
}

如果适用于您的情况,您可以将辅助类缓存到Dictionary<Type, object>中,以避免每次重新创建它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接