Activator.CreateInstance 与 Type.InvokeMember的区别

2024-06-08 05:44

本文主要是介绍Activator.CreateInstance 与 Type.InvokeMember的区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、使用 Activator.CreateInstance 创建实例
    • 1、使用 Activator.CreateInstance 的优点和缺点
    • 2、使用 Activator.CreateInstance 的代码示例
  • 二、使用 Type.InvokeMember 创建实例
    • 1、使用 Type.InvokeMember 的优点和缺点
    • 2、使用 Type.InvokeMember 的代码示例
  • 三、Activator.CreateInstance 与 Type.InvokeMember 的基准测试
    • 1、反射性能的 BenchmarkDotNet 设置
    • 2、Activator.CreateInstance 与 Type.InvokeMember对比
  • 四、Activator.CreateInstance 与 Type.InvokeMember 总结


一、使用 Activator.CreateInstance 创建实例

在 C# 中,Activator.CreateInstance方法是开发人员通过反射创建实例的最常用方法之一。它允许在运行时创建类的新实例,即使事先不知道它们的具体类型。此方法属于类,System.Activator通常用于需要动态实例化的场景。

的主要目的Activator.CreateInstance是动态创建类的实例 — 因此,如果您在编译时可以访问该类型,那么您可能没有充分的理由使用它!Activator.CreateInstance在要创建的对象类型直到运行时才知道的情况下,例如在加载插件或使用动态加载的程序集时,它特别有用。它消除了对硬编码显式构造函数的需求,并提供了对象创建的灵活性。

1、使用 Activator.CreateInstance 的优点和缺点

Activator.CreateInstance与普通对象实例相比,使用有几个优点:

允许后期绑定对象创建,这在对象类型在运行时可能发生变化的情况下很有用。
可以通过消除使用 switch 语句或 if-else 条件来处理不同对象类型的需求来简化代码库。
提供一种动态且可扩展的对象创建方法。
但是,使用时也需要考虑一些缺点Activator.CreateInstance:

由于运行时解析类型涉及额外的步骤,因此与直接实例化相比,使用反射的性能开销可能更高。
Activator.CreateInstance 通常依赖于公共无参数构造函数的存在。否则,您需要始终知道要传入哪些参数 — 如果您要针对许多不同类型动态执行此操作,则具有挑战性。
由于没有编译时检查签名兼容性,因此在修改目标类型时容易出现错误。

2、使用 Activator.CreateInstance 的代码示例

以下代码示例演示了如何使用Activator.CreateInstance动态创建实例:

// Example 1: Creating an instance of a known type
Type objectType = typeof(MyClass);
object instance = Activator.CreateInstance(objectType);

在示例 1 中,我们使用typeof获取Type代表已知类的对象MyClass。然后,我们使用Activator.CreateInstance创建 的新实例MyClass。

// Example 2: Creating an instance of an unknown type at runtime
string typeName = "MyNamespace.MyClass";
Type unknownType = Type.GetType(typeName);
object dynamicInstance = Activator.CreateInstance(unknownType);

在示例 2 中,我们有一个由字符串表示的未知类型typeName。我们使用根据提供的类型名称Type.GetType获取对象。最后,用于创建动态确定类型的新实例。TypeActivator.CreateInstance

我们再看一个例子,其中我们可以为构造函数传递参数——同样,假设我们知道签名,因为我们无法在编译时通过这种方法证明它:

// Example 3: Creating an instance with constructor parameters:
string typeName = "MyNamespace.MyClass";
Type unknownType = Type.GetType(typeName);
Object dynamicInstance = Activator.CreateInstance(unknownType,new[]{"Hello World!", //  this is the single string parameter!});

二、使用 Type.InvokeMember 创建实例

Type.InvokeMember是 DotNet 中 Reflection 提供的一种可用方法,允许我们动态创建类型的实例。它提供了一种灵活的方法,可以通过利用手头类型的信息在运行时实例化对象。出于这些原因,它在如何利用它来创建对象实例方面非常相似。

1、使用 Type.InvokeMember 的优点和缺点

Type.InvokeMember与普通对象实例相比,使用以下方法具有一些普遍的优点:

允许后期绑定对象创建,这在对象类型在运行时可能发生变化的情况下很有用。
可以通过消除使用 switch 语句或 if-else 条件来处理不同对象类型的需求来简化代码库。
提供一种动态且可扩展的对象创建方法。
等一下……这不就是我们上面看到的那个列表吗Activator.CreateInstance?没错。所以我们就简短地介绍一下这部分。除非我们开始研究性能,否则我们不会看到任何大的差异——也许在某些非常特殊的边缘情况下。但总的来说,两者都提供了非常全面的方法来动态实例化对象,而 InvokeMember 有点冗长,因为它处理的不仅仅是构造函数。

在进行基准测试之前,我们先检查一些代码。

2、使用 Type.InvokeMember 的代码示例

下面是一个示例代码片段,演示了如何Type.InvokeMember动态创建类型实例:

// Example 1: Creating an instance of a known type
Type objectType = typeof(MyClass);
var instance = objectType
.InvokeMember(null,BindingFlags.CreateInstance,null,null,null);

在上面的例子中,我们首先获取代表类“MyClass”的 Type 对象。然后我们使用 Type.InvokeMember 创建该类的实例并将其分配给“instance”变量。这使我们能够动态创建“MyClass”的对象,而无需明确指定类名。

而在编译时不知道类的情况下执行此操作与以前非常相似。但这部分与 InvokeMember 无关:

// Example 2: Creating an instance of an unknown type at runtime
string typeName = "MyNamespace.MyClass";
Type unknownType = Type.GetType(typeName);
var instance = objectType.InvokeMember(null,BindingFlags.CreateInstance,null,null,null);

最后,如果我们需要传递一些构造函数参数,那么我们也可以这样做:

// Example 3: Creating an instance with constructor parameters:
string typeName = "MyNamespace.MyClass";
Type unknownType = Type.GetType(typeName);
var instance = objectType.InvokeMember(null,BindingFlags.CreateInstance,null,null,new[]{"Hello World!",});

三、Activator.CreateInstance 与 Type.InvokeMember 的基准测试

1、反射性能的 BenchmarkDotNet 设置

我认为我们可以在三种情况下使用 BenchmarkDotNet 运行基准测试:

无参数构造函数类
具有单个字符串参数的构造函数
具有单个字符串参数的主构造函数
我想加入主构造函数,因为我知道这个特性会招致很多人的反对——最好还是获取一些数据吧!以下是我们将要实例化的类,供参考:

public class ParameterlessClass
{
}public class ClassicStringParameterClass
{private readonly string _value;public ClassicStringParameterClass(string value){_value = value;}
}public class PrimaryConstructorStringParameterClass(string _value)
{
}

至于基准测试,让我们看看我们将要运行的以下类。请记住,我使用它Activator.CreateInstance作为基线是因为我想比较Activator.CreateInstancevs Type.InvokeMember— 我只包括正常的构造函数路径作为参考。您也可以在 GitHub 上找到所有这些代码:

[ShortRunJob]
public class ParameterlessClassBenchmarks
{private Type? _type;[GlobalSetup]public void GlobalSetup(){_type = typeof(ParameterlessClass);}[Benchmark]public void Constructor(){var instance = new ParameterlessClass();}[Benchmark(Baseline = true)]public void Activator_Create_Instance(){var instance = Activator.CreateInstance(_type!);}[Benchmark]public void Type_Invoke_Member(){var instance = _type!.InvokeMember(null,BindingFlags.CreateInstance,null,null,null);}
}[ShortRunJob]
public class ClassicStringParameterClassBenchmarks
{private Type? _type;[GlobalSetup]public void GlobalSetup(){_type = typeof(ClassicStringParameterClass);}[Benchmark]public void Constructor(){var instance = new ClassicStringParameterClass("Hello World!");}[Benchmark(Baseline = true)]public void Activator_Create_Instance(){var instance = Activator.CreateInstance(_type!,new[]{"Hello World!",});}[Benchmark]public void Type_Invoke_Member(){var instance = _type!.InvokeMember(null,BindingFlags.CreateInstance,null,null,new[]{"Hello World!",});}
}[ShortRunJob]
public class PrimaryConstructorStringParameterClassBenchmarks
{private Type? _type;[GlobalSetup]public void GlobalSetup(){_type = typeof(PrimaryConstructorStringParameterClass);}[Benchmark]public void Constructor(){var instance = new PrimaryConstructorStringParameterClass("Hello World!");}[Benchmark(Baseline = true)]public void Activator_Create_Instance(){var instance = Activator.CreateInstance(_type!,new[]{"Hello World!",});}[Benchmark]public void Type_Invoke_Member(){var instance = _type!.InvokeMember(null,BindingFlags.CreateInstance,null,null,new[]{"Hello World!",});}
}

2、Activator.CreateInstance 与 Type.InvokeMember对比

当我们将这两种反射方法进行对比时,获胜者是…视情况而定。在最常见的一种情况下,我会说有一个非常明显的赢家,但对于其他情况,它们非常接近。但请务必阅读结论,因为这不是故事的结局。

我们要研究的第一个基准是无参数构造函数:
在这里插入图片描述

Activator.CreateInstance 与 Type.InvokeMember - 无参数构造函数的基准
这里明显胜出:Activator.CreateInstance几乎高出一个数量级。如果你的构造函数没有任何参数,那么最好的选择就是这个。

接下来,让我们检查Activator.CreateInstance一下Type.InvokeMember接受单个字符串参数的构造函数:
在这里插入图片描述

Activator.CreateInstance 与 Type.InvokeMember - 带参数的经典构造函数的基准
这两款车基本上势均力敌,尽管Activator.CreateInstance略胜一筹,但差距几乎可以忽略不计。

要查看的最后一个场景是主构造函数,在本例中,主构造函数接受一个字符串参数:
在这里插入图片描述

Activator.CreateInstance 与 Type.InvokeMember - 主构造函数的基准
获胜者:Type.InvokeMember,但只领先一点点。非常有趣的是,这与我们在之前的基准测试中看到的结果相反!

四、Activator.CreateInstance 与 Type.InvokeMember 总结

当谈到Activator.CreateInstancevs的性能结果时Type.InvokeMember,无参数构造函数的情况明显胜出:Activator.CreateInstance。但是当我们开始需要参数或使用带参数的主构造函数时,它开始均衡甚至有利于Type.InvokeMember。

这篇关于Activator.CreateInstance 与 Type.InvokeMember的区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041343

相关文章

Before和BeforeClass的区别及说明

《Before和BeforeClass的区别及说明》:本文主要介绍Before和BeforeClass的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Before和BeforeClass的区别一个简单的例子当运行这个测试类时总结Before和Befor

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Linux中的more 和 less区别对比分析

《Linux中的more和less区别对比分析》在Linux/Unix系统中,more和less都是用于分页查看文本文件的命令,但less是more的增强版,功能更强大,:本文主要介绍Linu... 目录1. 基础功能对比2. 常用操作对比less 的操作3. 实际使用示例4. 为什么推荐 less?5.

Java 关键字transient与注解@Transient的区别用途解析

《Java关键字transient与注解@Transient的区别用途解析》在Java中,transient是一个关键字,用于声明一个字段不会被序列化,这篇文章给大家介绍了Java关键字transi... 在Java中,transient 是一个关键字,用于声明一个字段不会被序列化。当一个对象被序列化时,被

解读@ConfigurationProperties和@value的区别

《解读@ConfigurationProperties和@value的区别》:本文主要介绍@ConfigurationProperties和@value的区别及说明,具有很好的参考价值,希望对大家... 目录1. 功能对比2. 使用场景对比@ConfigurationProperties@Value3. 核

Spring Boot拦截器Interceptor与过滤器Filter深度解析(区别、实现与实战指南)

《SpringBoot拦截器Interceptor与过滤器Filter深度解析(区别、实现与实战指南)》:本文主要介绍SpringBoot拦截器Interceptor与过滤器Filter深度解析... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实

关于Mybatis和JDBC的使用及区别

《关于Mybatis和JDBC的使用及区别》:本文主要介绍关于Mybatis和JDBC的使用及区别,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、JDBC1.1、流程1.2、优缺点2、MyBATis2.1、执行流程2.2、使用2.3、实现方式1、XML配置文件

exfat和ntfs哪个好? U盘格式化选择NTFS与exFAT的详细区别对比

《exfat和ntfs哪个好?U盘格式化选择NTFS与exFAT的详细区别对比》exFAT和NTFS是两种常见的文件系统,它们各自具有独特的优势和适用场景,以下是关于exFAT和NTFS的详细对比... 无论你是刚入手了内置 SSD 还是便携式移动硬盘或 U 盘,都需要先将它格式化成电脑或设备能够识别的「文

什么是ReFS 文件系统? ntfs和refs的优缺点区别介绍

《什么是ReFS文件系统?ntfs和refs的优缺点区别介绍》最近有用户在Win11Insider的安装界面中发现,可以使用ReFS来格式化硬盘,这是不是意味着,ReFS有望在未来成为W... 数十年以来,Windows 系统一直将 NTFS 作为「内置硬盘」的默认文件系统。不过近些年来,微软还在研发一款名

go 指针接收者和值接收者的区别小结

《go指针接收者和值接收者的区别小结》在Go语言中,值接收者和指针接收者是方法定义中的两种接收者类型,本文主要介绍了go指针接收者和值接收者的区别小结,文中通过示例代码介绍的非常详细,需要的朋友们下... 目录go 指针接收者和值接收者的区别易错点辨析go 指针接收者和值接收者的区别指针接收者和值接收者的