C#反射的学习,反射的一些注意事项,反射的一些使用代码的实例

这篇具有很好参考价值的文章主要介绍了C#反射的学习,反射的一些注意事项,反射的一些使用代码的实例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

c#反射

本文档写的的是C#中的反射常用的方式(附带示例代码)以及在使用的时候的一些注意事项。

八股文

C#中的反射是一种强大的机制,它允许在运行时动态地检查、访问和操作程序的元数据、类型信息和对象。以下是C#中反射常用的技巧和使用方式:

  1. 获取类型信息:使用Type类可以获取类型信息,如类名、命名空间、方法、字段等。你可以使用typeof操作符、GetType方法或通过对象实例获取类型信息。
  2. 创建对象:通过反射,你可以根据类型信息动态创建对象的实例,使用Activator.CreateInstance方法或Type的GetConstructor方法。
  3. 访问和修改字段和属性:反射允许你获取和设置对象的字段和属性值。你可以使用FieldInfo和PropertyInfo来实现。
  4. 调用方法:使用反射可以动态调用对象的方法。MethodInfo类允许你获得方法信息并调用它。
  5. 检查和调用构造函数:你可以使用反射检查和调用构造函数,使用ConstructorInfo类。
  6. 获取和设置属性值:使用PropertyInfo类可以获取和设置属性的值。
  7. 获取枚举成员:你可以使用反射获取枚举类型的成员,使用Enum.GetValues和Enum.GetNames方法。
  8. 处理泛型类型:反射允许你处理泛型类型,获取泛型参数,创建泛型类型的实例等。
  9. 动态装载程序集:你可以使用反射加载外部程序集,检查它们的内容,甚至实例化其中的类型。
  10. 自定义特性处理:你可以使用反射获取类型、方法、属性等的自定义特性(Attributes)信息,以实现元数据驱动的操作。
    使用反射时需要注意性能开销,因为它会涉及到运行时类型检查和动态方法调用,可能比直接编写静态代码更慢。因此,在正常情况下,应该尽量避免不必要的反射操作,特别是在性能敏感的应用中。

字段和属性的区别

字段没有get与set访问器文章来源地址https://www.toymoban.com/news/detail-737390.html

 public class MyClass
{
    private int myField; // 字段

    public int MyProperty // 属性
    {
        get { return myField; }
        set { myField = value; }
    }
}

注意事项

  1. 反射的参数建议使用nameof(类名.方法名),因为编译器会在编译时检查命名是否正确。
  2. 使用获取属性的方式去获取字段是会报空引用的
    获取属性使用:type.GetFields();type.GetField(name)
    获取字段使用:type.GetProperties(), type.GetProperty(name)
    获取方法使用:type.GetMethods(),type.GetMethod(name)
    获取接口使用:type.GetInterfaces()

示例代码

using System.Reflection;


DateTime beforDT = System.DateTime.Now;

FanShe();

DateTime afterDT = System.DateTime.Now;
TimeSpan ts = afterDT.Subtract(beforDT);
Console.WriteLine("DateTime总共花费{0}ms.", ts.TotalMilliseconds);
Console.ReadKey();


static void FanShe()
{
    //创建对象
    Man manObj = new Man();
    Type type = manObj.GetType();

    //获取所有字段
    Console.WriteLine("\n获取公开的字段");
    FieldInfo[] fieldInfos = type.GetFields();
    for (int f = 0; f < fieldInfos.Count(); f++)
    {
        Console.WriteLine("公开的字段有:" + fieldInfos[f].Name);
    }

    Console.WriteLine("\n获取特定字段并修改字段:");
    //字段与属性的区别,字段无getset访问器,属性有。
    FieldInfo fieldInfo_id = type.GetField(nameof(Animal.Age));
    fieldInfo_id.SetValue(manObj, 123);//设置Age为123
    Console.WriteLine("第一次修改是age字段是:" + fieldInfo_id.GetValue(manObj));//打印出Age
    fieldInfo_id.SetValue(manObj, 17);//设置Age为123
    Console.WriteLine("第二次修改是age字段是:" + fieldInfo_id.GetValue(manObj));//打印出Age

    Console.WriteLine("\n所有属性:");
    PropertyInfo[] properties = type.GetProperties();
    foreach (PropertyInfo property in properties)
    {
        Console.WriteLine(property.Name);
    }
    Console.WriteLine("\n获取特定属性并修改属性");
    PropertyInfo propertie_name = type.GetProperty(nameof(Man.Nationality));
    propertie_name.SetValue(manObj, "China");
    Console.WriteLine("第一次修改后的属性是" + propertie_name.GetValue(manObj));
    propertie_name.SetValue(manObj, "Japan");
    Console.WriteLine("第二次修改后的属性是" + propertie_name.GetValue(manObj));

    Console.WriteLine("/n获取实现的接口");
    Type[] interfaces = type.GetInterfaces();
    foreach (Type iface in interfaces)
    {
        Console.WriteLine(iface.Name);
    }


    Console.WriteLine("是否为空的判断");
    if (type.GetProperty(nameof(Man.Colour)) == null)
    {
        Console.WriteLine($"{nameof(Man.Colour)}not found.");
        return;
    }

    PropertyInfo manColour = type.GetProperty(nameof(Man.Colour));

    if (!manColour.CanWrite)
    {
        Console.WriteLine("Cannot write to Man.Colour property.");
        return;
    }
    manColour.SetValue(manObj, "yellow");//设置属性
    Console.WriteLine($"{nameof(manObj.Colour)}{manObj.Colour}");

    //获取到公开的方法
    MethodInfo[] methodInfos = type.GetMethods();
    for (int i = 0; i < methodInfos.Count(); i++)
    {
        Console.WriteLine(methodInfos[i].Name);
    }


    Console.WriteLine("\n调用无参的方法");
    MethodInfo methodInfo_popop = type.GetMethod(nameof(Man.Popop));
    methodInfo_popop.Invoke(manObj, null);

    Console.WriteLine("\n调用有参的方法");
    MethodInfo methodInfo_eatFood = type.GetMethod(nameof(Man.EatFood));
    methodInfo_eatFood.Invoke(manObj, new object[] { "香蕉", 123 });

    Console.WriteLine("\n调用无参数有返回值的方法");
    MethodInfo methodInfo_Speed = type.GetMethod(nameof(Man.Speed));
    object money = methodInfo_Speed.Invoke(manObj, new object[] { 123 });
    Console.WriteLine($"反射方法的返回值是:{money}");

    Console.WriteLine("\n调用接口无返回值无参数");
    MethodInfo speakingEnglishMethod = type.GetInterface(nameof(ILanguage)).GetMethod(nameof(Animal.SpeakingEnglish));
    speakingEnglishMethod.Invoke(manObj, null); // 输出: I can speak English.

    Console.WriteLine("\n调用接口无返回值有参数");
    MethodInfo speakJapaneseMethod = type.GetInterface(nameof(ILanguage)).GetMethod(nameof(Animal.SpeakJapanese));
    Console.WriteLine("返回是:" + "返回值是:" + speakJapaneseMethod.Invoke(manObj, null));

    Console.WriteLine("\n调用接口有返回值有参数");
    MethodInfo speakChineseMethod = type.GetInterface(nameof(ILanguage)).GetMethod(nameof(Animal.SpeakChinese));
    Console.WriteLine("返回值是:" + speakChineseMethod.Invoke(manObj, new object[] { "你好" }));

    Console.WriteLine("\n当与父类中有相同的方法的时候,调用父类中的同名方法");
    MethodInfo animalDoSexMethod = type.BaseType.GetMethod(nameof(Animal.DoSex));
    Console.WriteLine("父类中的方法" + animalDoSexMethod.Invoke(manObj, new object[] { "hei heihei" }));

    Console.WriteLine("\n当与父类中有相同的方法的时候,调用子类的同名方法");
    MethodInfo manDoSexMethod = type.GetMethod(nameof(Man.DoSex));
    Console.WriteLine("子类中的方法" + manDoSexMethod.Invoke(manObj, new object[] { "ha hhhaa" }));

    Console.WriteLine("\n子类调用重写的方法,\n当子类重写了父类的方法时,您可以通过子类类型来反射调用它。但是需要注意的是,在这种情况下,将始终调用子类中的方法版本,而不是父类中的版本。");
    MethodInfo drawMethod = type.GetMethod(nameof(Man.Draw));
    drawMethod.Invoke(manObj, new object[] { "山水" });

}

public class Man : Animal, ILanguage
{
    /// <summary>
    /// 国籍
    /// </summary>
    public string Nationality { get; set; }

    /// <summary>
    /// 肤色
    /// </summary>
    public string Colour { get; set; }

    /// <summary>
    /// 瞳孔颜色
    /// </summary>
    public string PupilColor;


    /// <summary>
    /// 说话
    /// </summary>
    /// <param name="word"></param>
    public void Say(string word)
    {
        Console.WriteLine("我说:" + word);
    }

    /// <summary>
    /// 花钱
    /// </summary>
    public int Speed(int money)
    {
        Console.WriteLine($"本次消费的金额是:{money}元。");
        return money;
    }

    /// <summary>
    /// 读书
    /// </summary>
    private void ReadBook()
    {
        Console.WriteLine("Reading book");
    }

    /// <summary>
    /// 交配
    /// </summary>
    /// <returns></returns>
    public new string DoSex(string targetName)
    {
        return $"is sexing with {targetName} ";
    }


    /// <summary>
    /// 画画
    /// </summary>
    /// <param name="drawName"></param>
    public override void Draw(string drawName)
    {
        Console.WriteLine($"这副{drawName}被我画好了");
    }


}

/// <summary>
/// 动物
/// </summary>
public class Animal : ILanguage
{

    /// <summary>
    /// 序号
    /// </summary>
    public int ID { get; set; }

    /// <summary>
    /// 姓名
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 性别
    /// </summary>
    public string Sex;

    /// <summary>
    /// 年龄
    /// </summary>
    public int Age;

    /// <summary>
    /// 是否开心
    /// </summary>
    public bool isHappy;

    /// <summary>
    /// 吃饭
    /// </summary>
    /// <param name="foodName"></param>
    /// <param name="foodcount"></param>
    public void EatFood(string foodName, int foodcount)
    {
        Console.WriteLine($"我吃了{foodcount}{foodName}");
    }

    /// <summary>
    /// 拉屎
    /// </summary>
    /// <returns></returns>
    public string Popop()
    {
        Console.WriteLine("is popoping");
        return "poping";
    }

    /// <summary>
    /// 交配
    /// </summary>
    /// <returns></returns>
    public string DoSex(string targetName)
    {
        return $"is sexing with {targetName} ";
    }

    public void SpeakingEnglish()
    {
        Console.WriteLine("i am speaking English, no return value and parameters.");
    }
    public string SpeakJapanese()
    {
        return "Speaking Japanese wrod";
    }

    public string SpeakChinese(string wrod)
    {
        return $"Chinese wrod:{wrod}";
    }

    /// <summary>
    /// 画画
    /// </summary>
    /// <param name="drawName"></param>
    public virtual void Draw(string drawName)
    {
        Console.WriteLine($"我正在画{drawName}");
    }

}

/// <summary>
/// 语言的接口
/// </summary>
public interface ILanguage
{
    /// <summary>
    /// 说英语
    /// </summary>
    void SpeakingEnglish();

    string SpeakJapanese();

    string SpeakChinese(string wrod);

}


到了这里,关于C#反射的学习,反射的一些注意事项,反射的一些使用代码的实例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 学习Linux的注意事项(使用经验;目录作用;服务器注意事项)

    本篇分享学习Linux过程中的一些经验 Linux严格区分大小写 Linux中所有内容以文件形式保存 ,包括硬件,Linux是以管理文件的方式操作硬件 硬盘文件是 /dev/sd[a-p] 光盘文件是 /dev/sr0 等 对于设置需要写入文件,命令行的设置在重启之后就会失效,只有下入文件才可以保存下来 文

    2024年02月11日
    浏览(55)
  • ES 一些简单 的查询注意事项

    term query 不分词字段 带分数 where name=xxx filter 分词字段 不分词字段 不带分数 Terms query 所有类型 带分数 where name in(xxx) Range query where name between xxx and xxx Exists Regexp Match query 分词字段/基础字段 Multi-match query 多个分词字段/基础字段 Boolean query 复合查询 must should 带分数 filter must

    2024年02月12日
    浏览(71)
  • Elasticsearch 一些异常报错、注意事项(1)

    系统支持通过参数(op_type=create)强制执行创建索引操作。只有当系统中不存在此文档的时候才会创建成功。如果不指定此操作类型,如果存在此文档则会进行更新操作。 bulk 默认op_type 是index 当创建文档的时候,如果不指定id,系统则会默认创建id。自动生成的id是一个不会重

    2023年04月08日
    浏览(20)
  • 手机怎么剪视频?分享一些剪辑工具和注意事项

    视频剪辑是一种将多个视频片段进行剪切、合并和编辑的技术,它可以帮助我们制作出精彩的视频作品。如今,随着智能手机的普及,我们可以随时随地使用手机进行视频剪辑。本文将为大家介绍一些手机剪辑工具和注意事项,帮助大家更好地进行视频剪辑。   首先,我们来

    2024年02月10日
    浏览(36)
  • Spring Data Elasticsearch 一些异常报错、注意事项(1)

    记录一:批量更新数据saveAll 引入maven依赖  saveAll批量新增,如果数据存在则会更新数据 记录二:批量更新数据Script脚本更新字段 参考:Script query | Elasticsearch Guide [8.5] | Elastic 记录三:空字段查询处理 如果查询字段createTime在ES数据中不存在,直接用.must(QueryBuilders.rangeQuery(

    2024年02月11日
    浏览(34)
  • Unity发布抖音小游戏的一些注意事项

    使用 webgl模式 发布抖音小游戏的一些注意事项 1.打包 使用webgl模式打包抖音小游戏,会因为找不到aapt工具导致打包失败 提示: aapt检查失败: sdk/build-tools/版本号。 解决方法:再unity hub里添加Android Build Support  2.黑屏问题 相机的HDR设为off 3.Text字体不见的问题 不能用unity自带的

    2024年02月11日
    浏览(30)
  • git常规操作流程(纯命令行操作)和一些注意事项

    当你在单位拿到了git仓库,并利用公司给你的OA账号和邮箱完成了你的git基础配置,下面就是使用命令行的无错固定操作流程 如果你很着急,你可以直接跳到最后的 总结部分 1.从仓库克隆代码到本地 这里的[codeUrl]就是你仓库的地址,当你在仓库点击图中绿色位置时,剪贴板复制的就

    2024年02月03日
    浏览(30)
  • 关于 Go 协同程序(Coroutines 协程)、Go 汇编及一些注意事项。

    参考:  Go 汇编函数 - Go 语言高级编程 Go 嵌套汇编 - 掘金 (juejin.cn) 前言: Golang 适用 Go-Runtime(Go 运行时,嵌入在被编译的PE可执行文件之中)来管理调度协同程式的运行。 Go 语言没有多线程(MT)的概念,在 Go 语言之中,每个 Go 协程就类似开辟了一个新的线程,效率上,肯

    2024年01月25日
    浏览(59)
  • MySQL5 和 MySQL8 的配置区别 & 一些注意事项

    先保证你的mysql正在运行,假如用户名是 root ,密码是 123456 ,运行下边的代码可以查看mysql的版本号。 这里我的版本是5.7.19。也就是5版本的。 注意:下边的url区别不用管。看到这就可以了。 当然8版本的后边不写也没事。 不建议在没有服务器身份验证的情况下建立SSL连接。

    2024年02月05日
    浏览(28)
  • C# 获取Windows系统版本注意事项

    首先通过微软官方文档:https://learn.microsoft.com/zh-cn/windows/win32/sysinfo/operating-system-version了解各个操作系统对应的版本号  下面介绍3种获取版本号的方式及弊端 1. Environment.OSVersion.Version 该方式适合.NET Framework,并且 必须添加应用程序清单文件,并且需要把程序应用程序清单文

    2024年02月10日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包