知道泛型类定义以及T对应的Type,如何获取泛型类的Type

本文讨论了如何在已知泛型类TestResult<T>及其参数类型TestObjOne的情况下,通过代码操作获取TestResult<TestObjOne>的Type,包括使用AssemblyQualifiedName、Json序列化和动态类型的转换。同时也提及了协变逆变的概念以及使用Mapper类简化赋值过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看标题是不是很迷惑,其实用代码描述更直观。就是现在知道泛型类定义G<T>,也知道T对应的Type,如何获取G<T>对应的Type

现在有如下类,符合上面描述对应的类定义。

    public class TestObj
    {
        public string ObjId { get; set; } = Guid.NewGuid().ToString();
    }
    public class TestObjOne : TestObj
    {
        public string Name { get { return "One"; } }
    }
    public class TestResult<T>
        where T : TestObj
    {
        public string SomeProp { get; set; }
        public T Object { get; set; }
    }

也就是说我现在知道有泛型类TestResult<T>,也知道T对应的类型是typeof(TestObjOne),如何得到typeof(TestResult<TestObjOne>)?

也许有人会说,上面的typeof(TestResult<TestObjOne>)不是已经拿到想要的类型了吗?但问题在代码里这是硬编码啊,就上面描述的场景写不出来的啊!

通过对比typeof(TestResult<>)typeof(TestResult<TestObjOne>),可以发现Type.AssemblyQualifiedName非常的有规律,两者的差异在于方括号以内。

TestResult<>:
ConsoleDemo.TestResult`1, ConsoleDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
TestResult<TestObjOne>:
ConsoleDemo.TestResult`1[[ConsoleDemo.TestObjOne, ConsoleDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], ConsoleDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

那这样是不是可以通过字符串的操作,得到最终想要的Type呢?测试下来,的确可以,所以有了下面的代码:

        public static Type GetGenericTypeWithParameter(Type tParamType,Type genericType)
        {
            if (tParamType == null)
            {
                throw new ArgumentNullException(nameof(tParamType));
            }
            if (genericType == null)
            {
                throw new ArgumentNullException(nameof(genericType));
            }
            if (!genericType.IsGenericType)
            {
                throw new ArgumentException("Not generic type");
            }
            if (genericType.GenericTypeArguments.Length > 0)
            {
                throw new ArgumentException("Generic type has arguments");
            }
            if (tParamType.IsAbstract || tParamType.IsInterface)
            {
                throw new ArgumentException("Not supported");
            }
            var gTypeString = genericType.AssemblyQualifiedName;
            var idx = gTypeString.IndexOf(',');
            var fString = $"{gTypeString.Substring(0, idx)}[[{tParamType.AssemblyQualifiedName}]]{gTypeString.Substring(idx)}";
            return Type.GetType(fString);
        }

好吧,现在有这样一个场景,有一段字符串是typeof(TestResult<TestObjOne>)对应Json序列化后的结果,但最终返回给外部时为了统一返回返回的是TestResult<TestObj>,然后发现问题又来了,下面的代码编译过不了

        static TestResult<TestObj> Get()
        {
            return new TestResult<TestObjOne>();
        }

换个思路尝试,编译不报错,返回null了……

        static TestResult<TestObj> Get()
        {
            return new TestResult<TestObjOne>() as TestResult<TestObj>;
        }

有人可能说那就考虑协变逆变啊,但协变逆变是基于接口定义的,为了这个将贫血模型还要定义接口好像有点过了,而且协变逆变用起来也有点难度。

那是不是还有其它方式呢?事实肯定是的啊,我们用最笨的方法,自己new实例返回呗!

var jsonStr="";
var type = GetGenericTypeWithParameter(typeof(TestObjOne),typeof(TestResult<>));
dynamic data = JsonConvert.DeserializeObject(jsonStr, type);
if(data!=null)
{
	return new TestResult<TestObj>
	{
		SomeProp=data.SomeProp,
		Object=data.Object,
	};
}
return null;

注意上面的代码最后用了dynamic,这样就可以不用通过再反射赋值的方式来处理,当然如果泛型类属性很多的话,也可以引入Mapper类来避免手工赋值的情况。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值