首页 > 编程语言 >C#反射

C#反射

时间:2023-05-01 16:13:19浏览次数:46  
标签:反射 Console string C# System using Id

C#反射简介

反射(Reflection)是C#语言中一种非常有用的机制,它可以在运行时动态获取对象的类型信息并且进行相应的操作。反射是一种在.NET Framework中广泛使用的技术,它是实现上述特性的基础,非常重要。

反射能干什么?

使用反射可以让我们在运行时动态地获取对象的类型信息并进行相应的操作,比如创建对象、调用方法、获取属性等。举个简单的例子,我们在写代码时,为了能够调用某个对象的方法,我们通常需要先创建这个对象的实例,然后才能调用其方法。而使用反射机制,我们可以在运行时动态地创建对象并直接调用其方法,而不必提前定义它们。

反射的基本使用

反射的核心是Type类,它表示.NET Framework中的类型,即类、结构体、枚举等。我们可以使用Type类来获取程序集中定义的类型,获取类型的成员,创建类型的实例等等。下面我们举几个反射的基本使用案例。

1. 获取类型信息

获取类型信息是反射最基本的用法之一,我们可以使用Type类的静态方法GetType获取类型信息,如下所示。

using System;
namespace ReflectionDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Type type = typeof(string);
            Console.WriteLine(type.FullName);
            Console.ReadKey();
        }
    }
}

这个例子中,我们获取了string类型的Type对象,然后输出了这个对象的FullName属性,也就是string类型的完全限定名称System.String。

2. 反射创建对象

使用反射可以在运行时动态地创建对象,这极大地方便了我们的编程工作。例如,我们通常要编写一个工厂类来根据不同的类型创建不同的对象,而使用反射则可以在不需要工厂类的情况下创建对象。下面是一个简单的例子。

using System;
using System.Reflection;

namespace ReflectionDemo
{
    class MyClass
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // 获取 MyClass 的类型对象
            Type myClassType = typeof(MyClass);

            // 创建 MyClass 类型的实例
            MyClass myClass = (MyClass)Activator.CreateInstance(myClassType);

            // 设置对象属性值
            PropertyInfo propId = myClassType.GetProperty("Id");
            propId.SetValue(myClass, 100);

            PropertyInfo propName = myClassType.GetProperty("Name");
            propName.SetValue(myClass, "Tom");

            // 打印对象属性值
            Console.WriteLine(myClass.Id);
            Console.WriteLine(myClass.Name);

            Console.ReadLine();
        }
    }
}

上述代码中,我们首先获取了 MyClass 类型的对象,然后调用 Activator.CreateInstance 方法来创建该类型的实例。接着,我们利用 PropertyInfo 对象获取、设置对象的属性值,最后打印属性值。以上就是用反射机制在 C# 中创建对象的过程。

3. 反射调用方法

使用反射可以在运行时动态地调用对象的方法。我们可以使用MethodInfo类来获取方法信息,然后调用MethodInfo.Invoke方法来调用这个方法,如下所示。

using System;
using System.Reflection;
namespace ReflectionDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Type type = typeof(string);
            MethodInfo method = type.GetMethod("ToUpper", new Type[] { });
            string result = (string)method.Invoke("Hello World", null);
            Console.WriteLine(result);
            Console.ReadKey();
        }
    }
}

这个例子中,我们获取了string类型的ToUpper方法信息,然后使用Invoke方法调用这个方法,将字符串"Hello World"转化为大写输出。

反射的高级用法

反射的高级用法是指使用反射来实现更高级的编程功能,比如泛型、LINQ等。下面我们举几个例子展示反射的高级用法。

1. 获取泛型方法信息

使用反射可以在运行时动态地获取泛型方法的信息,然后在运行时构造泛型类型。下面是一个例子。

 
using System;
using System.Reflection;
namespace ReflectionDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Type type = typeof(Program);
            MethodInfo method = type.GetMethod("TestMethod");
            MethodInfo genericMethod = method.MakeGenericMethod(typeof(string));
            genericMethod.Invoke(null, null);
            Console.ReadKey();
        }
        public static void TestMethod<T>()
        {
            Console.WriteLine(typeof(T).FullName);
        }
    }
}

这个例子中,我们使用GetMethod方法获取了TestMethod方法信息,然后使用MakeGenericMethod方法构造了泛型方法,并将其转化为MethodInfo类进行输出。

2. 在运行时构造LINQ查询

使用反射可以在运行时动态地根据查询条件构造LINQ查询。下面是一个例子。

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace ReflectionDemo
{
    class MyEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // 构造查询条件
            string fieldName = "Id";
            int fieldValue = 100;

            // 获取运行时类型和字段信息
            Type entityType = typeof(MyEntity);
            PropertyInfo property = entityType.GetProperty(fieldName);

            // 使用表达式树构造查询条件
            ParameterExpression parameter = Expression.Parameter(entityType, "x");
            MemberExpression member = Expression.Property(parameter, property);
            ConstantExpression constant = Expression.Constant(fieldValue, property.PropertyType);
            BinaryExpression equal = Expression.Equal(member, constant);
            Expression<Func<MyEntity, bool>> expression = Expression.Lambda<Func<MyEntity, bool>>(equal, parameter);

            // 执行查询
            IQueryable<MyEntity> entities = new List<MyEntity>
            {
                new MyEntity { Id = 100, Name = "Alice" },
                new MyEntity { Id = 200, Name = "Bob" },
                new MyEntity { Id = 300, Name = "Charlie" },
                new MyEntity { Id = 400, Name = "David" },
            }.AsQueryable();
            IQueryable<MyEntity> query = entities.Where(expression);

            // 输出查询结果
            foreach (MyEntity entity in query)
            {
                Console.WriteLine($"Id={entity.Id}, Name={entity.Name}");
            }

            Console.ReadLine();
        }

        static object CreateWhereLambda(Type elementType)
        {
            MethodInfo whereMethod = typeof(Program).GetMethod(nameof(CreateWhereLambdaImpl), BindingFlags.NonPublic | BindingFlags.Static);
            return whereMethod.MakeGenericMethod(elementType).Invoke(null, null);
        }

        static Func<T, bool> CreateWhereLambdaImpl<T>()
        {
            return item => (int)(object)item % 2 == 0;
        }
    }
}

在上述示例中,我们首先定义了一个查询条件,然后获取了运行时类型和字段信息,接着使用表达式树构造了查询条件,并利用反射执行了 LINQ 查询。最终,我们输出的结果只包括 Id 等于 100 的实体。

反射使用的注意事项

使用反射需要格外注意性能和安全问题,一些常见的注意事项包括:

  1. 尽量使用已经编译好的程序集,避免使用动态编译的程序集。
  2. 反射的性能较低,尽量少用。
  3. 反射有漏洞,应注意安全问题。
  4. 授权可以防止反射的滥用,应根据实际情况授权反射使用权限。

总结

通过本文的学习,我们了解了反射的基本概念和使用方法,并且掌握了反射的高级用法。反射在C#中是一项非常强大且必要的技术,如果恰当地使用它,可以使我们的编程工作变得更加高效和便捷。同时,我们也需要格外注意反射使用过程中的性能和安全问题,做好样本授权等工作,以便更好地使用反射这个强大的功能。

 

标签:反射,Console,string,C#,System,using,Id
From: https://www.cnblogs.com/xiaofeixiaa/p/17366578.html

相关文章

  • 动态主题库Colorful,容易地改变App的配色方案
    Colorful是一个动态主题库,允许您很容易地改变App的配色方案在Application中初始化ColorfulpublicclassSampleAppextendsApplication{@OverridepublicvoidonCreate(){super.onCreate();Colorful.init(this);}}如......
  • [ABC148F] Playing Tag on Tree
    2023-03-04题目题目传送门翻译翻译难度&重要性(1~10):5题目来源AtCoder题目算法最短路解题思路考虑到T想活得久,A想尽早追上T,所以我们就将问题转化为在树上找一条最长链,使得T能比A先到达这条链。所以我们就可以在树上跑两遍单源最短路,因为边权为\(1\),所以......
  • android5.0使用Notification报RemoteServiceException的解决办法
    有时android5.0下使用Notification会报如下错误信息(比如开启重启动系统就要发送通知)android.app.RemoteServiceException:Badnotificationpostedfrompackage*:Couldn'tcreateicon:StatusBarIcon这个问题多数集中在setSmallIcon(R.drawable.scan......
  • tomcat+nginx实现项目部署
      本文主要讲述的项目部署方面的一些基础知识,tomcat+nginx的环境。nginx是常用的web服务器,用于获取静态资源,类似的服务器还有apache。tomcat是基于javaservlet的web容器,用于获取动态资源。一般的web服务架构:前端部署nginx,后端部署tomcat。用户访问nginx,静态......
  • c语言基础
    环境设置c程序的源文件通常使用扩展名.cc程序需要编译成机器语言,这样cpu可以按给定指令执行程序。最常用的编译器是gcc(mac上xcode就可以)程序结构#include预处理器指令,类似于import,主要用于告诉编译器,我们要引入什么。.h结尾的是头文件,头文件中一般是定义的结构体和变量#include......
  • 10分钟搞定!C++类中构造函数和析构函数的完全指南
    一、初步认识构造函数1.什么是构造函数?要了解构造函数就要先了解一下,类的6个默认成员函数,如下图:构造函数:构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。通俗一点来......
  • C# 调用 C dll char* callback 设置回调函数不定参数
    1:C#调用返回字符串C++nativedll函数的注意事项:a:C++DLL的返回值,安全的做法是分配一个全局char数组,把要返回的char*复制到这个char数组中, charbuff[255];constchar*__stdcallReturnString(){strcpy(buff,"xxxxxxxxxxxxxxx");returnbuff;}......
  • doceker 安装
     CentOSDocker安装Docker支持以下的CentOS版本:CentOS7(64-bit)CentOS6.5(64-bit)或更高的版本 前提条件目前,CentOS仅发行版本中的内核支持Docker。Docker运行在CentOS7上,要求系统为64位、系统内核版本为3.10以上。Docker运行在CentOS-6.5或更高的版本的Ce......
  • centos7 安装centos桌面
    一、输入命令yumgroupinstall"GNOMEDesktop""GraphicalAdministrationTools"二、设置系统启动等级。systemctlget-default#获取当前系统运行形式,会显示multi-user.target(命令行终端),或者:graphical.targetsystemctlset-defaultgraphical.target#设置默认启动为图形界面,re......
  • HTML5+CSS3
    CSS3HTMLHTML总结......