C#根据名称字符串创建对象(泛型类与泛型方法)

目录

序言

一、先定义两个模型

二、开始生成模式实例,调用方法。

2.1 调用普通类中普通方法

2.2-调用普通类中泛型方法

2.3-调用泛型类中泛型方法

三、参考文章

3.1-《c#根据字符串创建对象实例》

3.2-《C# 根据字符串生成对象——使用反射》

3.3-《C#如何根据字符串动态的创建对象(类)?》

3.4-《C# 动态创建实例化泛型对象,实例化新对象 new()》

3.5-《C# 通过反射来动态创建泛型类型》

3.6-《MethodInfo.MakeGenericMethod(Type[]) 方法》

3.7-《Type.MakeGenericType(Type[]) 方法》


序言

在C#中,某些场景下,需要根据类的完全限定字符串(就是类名的字符串),动态的实例化对象。

这里最为复杂的,就是根据类名字符串来实例化泛型类与其中的泛型方法了。

下面由简入繁,逐一展示一下如何实现。总体而言,还是使用反射技术,先生成类实例,再调用方法。

注意:只是使用泛型类已定义泛型(如泛型T、泛型R)的方法,不能称为泛型方法,需要有自己的泛型(如泛型U)才能叫泛型方法。

一、先定义两个模型

//普通类
    internal class MyClass
    {
        public string Name { get; set; } = string.Empty;
        public string Mes { get; set; } = string.Empty;
        
        public MyClass() 
        { }
        public MyClass(string name, string mes)
        {
            Name = name;
            Mes = mes;
        }

        public void MyMethod(IProgress<string> progress)
        {
            if (string.IsNullOrEmpty(Name) && string.IsNullOrEmpty(Mes))
            {
                progress?.Report("你调用的是普通类中的普通方法,该类构造函数无参。");
            }
            else
            {
                progress?.Report($"你调用的是普通类中的普通方法,该类构造函数有参,Name={Name}");
            }
        }

        public void MyMethodTR<T, R>(IProgress<string> progress)
        {
            progress?.Report($"调用普通类中的泛型方法,泛型T名称:{typeof(T)},泛型R名称:{typeof(R)}。");
        }
    }

    //泛型类
    internal class MyClass<T, R>
        where T : class
        where R : class
    {
        public string Name { get; set; } = string.Empty;
        public string Mes { get; set; } = string.Empty;
        public string TName { get; set; } = string.Empty;//泛型类型的名称
        public string RName { get; set; } = string.Empty;

        public MyClass() 
        { }
        public MyClass(string name, string mes, T t, R r)
        {
            Name = name;
            Mes = mes;
            TName = t.GetType().Name;
            RName = r.GetType().Name;
        }

        public void MyMethod(IProgress<string> progress)
        {
            if (string.IsNullOrEmpty(Name) && string.IsNullOrEmpty(Mes))
            {
                progress?.Report($"你调用的是泛型类无参构造函数,泛型T名称:{typeof(T)},泛型R名称:{typeof(R)}。");
            }
            else
            {
                progress?.Report($"你调用的是泛型类有参构造函数,泛型T名称:{typeof(T)},泛型R名称:{typeof(R)}。");
            }
        }

        //泛型方法
        public void MyMethodU<U>(IProgress<string> progress, T t)
        {
            //只有使用新的泛型U的方法才称之为泛型方法,使用泛型T、R的都不能称之为泛型方法。
            progress?.Report($"泛型类中泛型方法,泛型U名称:{typeof(U)},泛型T实例内容:{t}。");
        }
    }

二、开始生成模式实例,调用方法。

2.1 调用普通类中普通方法

void CreatMethodInClass(IProgress<string> progress) 
        {
            //【1、创建普通类】
            //typeFullName = 类的完全限定名(即包括命名空间)
            string typeFullName = "LearnCreatClassByString.Models.MyClass";
            object[] argsC = new object[] { "wxy", "HelloWorld" };//构造函数用的参数
            Type? typeC = Type.GetType(typeFullName);
            if (typeC != null)
            {
                var tC = Activator.CreateInstance(typeC, argsC);//调用带参构造函数
                //var tC = Activator.CreateInstance(type, null);//调用无参构造函数
                if (tC is MyClass p)
                {
                    //【2、调用普通方法】
                    // 2-1、根据名称调用
                    MethodInfo? mio = typeC.GetMethod("MyMethod");
                    if (mio is MethodInfo mi)
                    {
                        object[] argsM = { progress };
                        mi.Invoke(p, argsM);
                    }
                    // 2-2、直接调用
                    p.MyMethod(progress);
                }
                else
                { }
            }
            else
            { }
        }

2.2-调用普通类中泛型方法

void CreatTRMethodInClass(IProgress<string> progress)
        {
            //【1、创建普通类】
            //typeFullName = 类的完全限定名(即包括命名空间)
            string typeFullName = "LearnCreatClassByString.Models.MyClass";
            object[] argsC = new object[] { "wxy", "HelloWorld" };//构造函数用的参数
            Type? typeC = Type.GetType(typeFullName);
            if (typeC != null)
            {
                var tC = Activator.CreateInstance(typeC, argsC);//调用带参构造函数
                //var tC = Activator.CreateInstance(type, null);//调用无参构造函数
                if (tC is MyClass p)
                {
                    //【2、调用泛型方法】
                    // 2-1、根据名称调用
                    MethodInfo? mio = typeC.GetMethod("MyMethodTR");
                    if (mio is MethodInfo mi)
                    {
                        Type[] typeMArgs = { typeof(int), typeof(string) };
                        MethodInfo miConstructed = mi.MakeGenericMethod(typeMArgs);
                        object[] argsM = { progress };
                        miConstructed.Invoke(p, argsM);
                    }
                    // 2-2、直接调用
                    p.MyMethodTR<int, string>(progress);
                }
                else
                { }
            }
            else
            { }
        }       

2.3-调用泛型类中泛型方法

void CreatTRMethodInTRClass(IProgress<string> progress)
        {
            //【1、创建泛型类】
            // 获取当前程序集
            Assembly assembly = Assembly.GetExecutingAssembly();  
            //Assembly assembly = Assembly.Load("LearnCreatClassByString");//方式2
            /*【关键】
             * 获取泛型类的完全限定名(即包括命名空间)
             * typeFullName第二个字符串中的【`2】表示泛型参数占位符个数。
             * 一个泛型参数则表示为:`1,多个泛型参数则表示为:`N;
             */
            string typeFullName = "LearnCreatClassByString.Models.MyClass" + "`2";
            var genericC = assembly.GetType(typeFullName);
            if (genericC != null)
            {
                Type[] typeCArgs = { typeof(string), typeof(string) };
                Type constructedC = genericC.MakeGenericType(typeCArgs);
                object[] argsC = new object[] { "wxy", "HelloWorld", "Twxy", "Rwxy" };
                var tC = Activator.CreateInstance(constructedC, argsC);
                if (tC is MyClass<string, string> p)
                {
                    p.MyMethod(progress);

                    //【2、调用泛型方法】
                    // 2-1、根据名称调用
                    MethodInfo? mio = constructedC.GetMethod("MyMethodU");
                    if (mio is MethodInfo mi)
                    {
                        Type[] typeMArgs = { typeof(string) };
                        MethodInfo miConstructed = mi.MakeGenericMethod(typeMArgs);
                        string tString = "光使用泛型类泛型T、R的方法,不能称为泛型方法,需要有自己的泛型才能叫泛型方法。";
                        object[] argsM = { progress, tString };//第2个参数是:T t,T是泛型类中的T。
                        miConstructed.Invoke(p, argsM);
                    }
                    // 2-2、直接调用
                    progress.Report("方式2:直接调用泛型方法。");
                    p.MyMethodU<int>(progress, "直接调用泛型方法。");
                }
                else
                { }
            }
            else
            { }
        }      

三、参考文章

3.1-《c#根据字符串创建对象实例》

https://blog.csdn.net/xuwei_xuwei/article/details/36182041

3.2-《C# 根据字符串生成对象——使用反射》

https://blog.csdn.net/q__y__L/article/details/103159234

3.3-《C#如何根据字符串动态的创建对象(类)?》

https://bbs.csdn.net/topics/250049825

3.4-《C# 动态创建实例化泛型对象,实例化新对象 new()》

https://www.cnblogs.com/lfzm/p/9801367.html

3.5-《C# 通过反射来动态创建泛型类型》

https://www.cnblogs.com/mq0036/p/15346470.html

3.6-《MethodInfo.MakeGenericMethod(Type[]) 方法》

MethodInfo.MakeGenericMethod(Type[]) 方法 (System.Reflection) | Microsoft Learn

3.7-《Type.MakeGenericType(Type[]) 方法》

Type.MakeGenericType(Type[]) 方法 (System) | Microsoft Learn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值