C# 反射

反射

System.Reflection,.NET框架提供的帮助类库

好处:动态的

缺点:编写复杂,避开编译器检查,性能问题

GetType()typeof() 都是在编程中用于获取类型信息的常用方法或操作符,但它们之间有一些重要的区别。这里我将以C#为例来说明它们之间的区别和作用,因为这两个概念在C#中非常常见。

1. GetType()

GetType() 是一个实例方法,它属于 System.Object 类,这意味着所有在C#中创建的类都继承了此方法。因此,你可以在任何对象实例上调用 GetType() 来获取该对象的运行时类型。

作用

  • 获取对象实例的运行时类型。
  • 通常用于反射(Reflection)或类型检查。

示例

csharp 复制代码
string str = "Hello, World!";
Type type = str.GetType(); // type 现在是 String 类型

2. typeof()

typeof() 是一个C#操作符,用于在编译时获取类型信息。它接受一个类型名称(而非实例)作为参数,并返回表示该类型的 System.Type 对象。

作用

  • 获取类型的编译时信息。
  • 常用于泛型编程、条件编译和类型检查。

示例

csharp 复制代码
Type type = typeof(string); // type 现在是 String 类型

区别

  • 调用方式GetType() 是一个实例方法,需要在对象实例上调用;而 typeof() 是一个操作符,用于获取类型的静态信息。
  • 执行时间GetType() 在运行时执行,因此它可以获取对象实例的实际类型(即使该实例是某个类型的子类实例);而 typeof() 在编译时执行,因此它只能获取到你在代码中明确指定的类型。
  • 用途 :由于上述的执行时间差异,GetType() 通常用于反射和动态类型检查;而 typeof() 则常用于泛型编程和编译时类型检查。

实际上,GetType() 方法是在反射中常用的,因为它允许你在运行时获取对象的实际类型,而不仅仅是编译时声明的类型。而 typeof 关键字则通常用于在编译时获取类型信息,它并不直接用于反射,但在与反射相关的操作中可能间接用到。

下面是一个使用 GetType() 方法进行反射的示例:

csharp 复制代码
using System;
using System.Reflection;

class MyClass
{
    public void MyMethod()
    {
        Console.WriteLine("MyClass.MyMethod called");
    }
}

class Program
{
    static void Main()
    {
        MyClass myObj = new MyClass();

        // 使用GetType()方法获取对象的类型
        Type type = myObj.GetType();

        // 使用反射调用MyMethod方法
        MethodInfo methodInfo = type.GetMethod("MyMethod");
        if (methodInfo != null)
        {
            methodInfo.Invoke(myObj, null); // 调用无参的MyMethod方法
        }
    }
}

在这个示例中,我们创建了一个 MyClass 的实例 myObj,并使用 GetType() 方法获取了它的类型。然后,我们使用 Type 对象的 GetMethod() 方法来获取 MyMethod 方法的 MethodInfo 对象。最后,我们使用 MethodInfo 对象的 Invoke() 方法来调用该方法。

typeof 关键字在反射中可能间接使用,比如当你需要获取一个类型的 Type 对象但又没有该类型的实例时:

csharp 复制代码
Type type = typeof(MyClass); // 获取MyClass的Type对象,而不需要MyClass的实例

在这个例子中,我们使用 typeof(MyClass) 来直接获取 MyClass 类型的 Type 对象,而不需要创建 MyClass 的实例。这在静态类型检查和泛型编程中特别有用。但是,请注意,这并没有直接参与反射操作,而是为反射提供了类型信息。

作用

1.动态类型信息

csharp 复制代码
using System;
using System.Reflection;

public class MyClass
{
    public int MyProperty { get; set; }
    public void MyMethod() { }
}

class Program
{
    static void Main()
    {
        Type type = typeof(MyClass);
        Console.WriteLine("Type Name: " + type.Name); // 输出 "MyClass"
        Console.WriteLine("Base Type: " + type.BaseType.Name); // 输出 "Object"

        // 获取所有公共属性
        PropertyInfo[] properties = type.GetProperties();
        foreach (var property in properties)
        {
            Console.WriteLine("Property: " + property.Name);
        }

        // 获取所有公共方法
        MethodInfo[] methods = type.GetMethods();
        foreach (var method in methods)
        {
            Console.WriteLine("Method: " + method.Name);
        }
    }
}

2. 动态对象实例化

csharp 复制代码
using System;
using System.Reflection;

public class MyClass
{
    public string Message { get; set; }
}

class Program
{
    static void Main()
    {
        Type type = typeof(MyClass);
        object instance = Activator.CreateInstance(type); // 创建 MyClass 的实例

        // 假设 MyClass 有一个公共的无参构造函数
        // 如果需要带参数的构造函数,请使用带参数的 Activator.CreateInstance 方法

        // 通过反射设置属性值
        PropertyInfo property = type.GetProperty("Message");
        property.SetValue(instance, "Hello, Reflection!");

        // 通过反射获取属性值
        string message = (string)property.GetValue(instance);
        Console.WriteLine(message); // 输出 "Hello, Reflection!"
    }
}

3. 动态方法调用

csharp 复制代码
using System;
using System.Reflection;

public class MyClass
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

class Program
{
    static void Main()
    {
        Type type = typeof(MyClass);
        object instance = Activator.CreateInstance(type); // 创建 MyClass 的实例

        // 获取 Add 方法的 MethodInfo
        MethodInfo method = type.GetMethod("Add");

        // 调用 Add 方法并传入参数
        object result = method.Invoke(instance, new object[] { 1, 2 });

        // 输出结果
        Console.WriteLine((int)result); // 输出 3
    }
}

4. 动态属性访问(已在 2 中包含)

5. 动态程序集加载

csharp 复制代码
using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        // 加载程序集(这里假设你有一个名为 "MyAssembly.dll" 的程序集)
        Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");

        // 获取程序集中的类型
        Type type = assembly.GetType("MyAssembly.MyClass");

        // 后续可以创建实例、调用方法等...
    }
}

请注意,由于动态加载程序集通常涉及文件系统上的文件,因此上述示例中的 "MyAssembly.dll" 需要替换为实际的程序集文件名和路径。

6. 自定义序列化

csharp 复制代码
using System;
using System.IO;
using System.Reflection;

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

class Program
{
    static void Main()
    {
        MyClass obj = new MyClass { Id = 1, Name = "Test" };

        // 自定义序列化方法,使用反射获取属性值
        string serialized = SerializeObject(obj);
        Console.WriteLine(serialized); // 输出类似 "{Id: 1, Name: Test}"

        // 假设有一个反序列化方法(这里省略实现细节)
        MyClass deserialized = DeserializeObject<MyClass>(serialized);
        Console.WriteLine($"Id: {deserialized.Id}, Name: {deserialized.Name}"); // 输出 "Id: 1, Name: Test"
    }

    static string SerializeObject(object obj)
    {
        Type type = obj.GetType();
        var properties = type.GetProperties();

        using (var sw = new StringWriter())
        {
            sw.Write("{");
            bool first = true;
            foreach (var property in properties)
            {
                if (!first) sw.Write(", ");
                first = false;
                sw.Write($"{property.Name}: {property.GetValue(obj, null)}");
            }
            sw.Write("}");

            return sw.ToString();
        }
    }

    static T DeserializeObject<T>(string serialized)
    {
        // 这里省略了反序列化的实现细节,因为这会涉及到解析字符串和设置对象属性的逻辑
        throw new NotImplementedException();
    }
}

7. 框架和库开发(示例可能很抽象)

框架和库开发的示例通常涉及更复杂的逻辑,但这里可以用一个简单的依赖注入容器示例来展示反射的使用:

csharp 复制代码
using System;
using System.Reflection;

public interface IService
{
    void DoWork();
}

public class MyService : IService
{
    public void DoWork()
    {
        Console.WriteLine("Service is working.");
    }
}

public class ServiceContainer
{
    private readonly Type _serviceType;

    public ServiceContainer(Type serviceType)
    {
        _serviceType = serviceType;
    }

    public IService Resolve()
    {
        return (IService)Activator.CreateInstance(_serviceType);
    }
}

class Program
{
    static void Main()
    {
        ServiceContainer container = new ServiceContainer(typeof(MyService));
        IService service = container.Resolve();
        service.DoWork(); // 输出 "Service is working."
    }
}

8. 单元测试(使用 NUnit 框架作为示例)

csharp 复制代码
using NUnit.Framework;
using System.Reflection;

public class MyClass
{
    // ... 类的其他成员 ...

    private int PrivateMethod()
    {
        return 42; // 假设这是一个私有方法
    }
}

[TestFixture]
public class MyClassTests
{
    [Test]
    public void TestPrivateMethod()
    {
        MyClass obj = new MyClass();

        // 使用反射调用私有方法
        MethodInfo method = typeof(MyClass).GetMethod("PrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
        int result = (int)method.Invoke(obj, null);

        Assert.AreEqual(42, result);
    }
}

9. 反编译器工具(这通常是一个独立的应用,不直接写代码示例)

反编译器工具(如 ILSpy、dotPeek 等)使用反射的概念来读取和解析 .NET 程序集(DLL 或 EXE 文件),但它们并不是通过 C# 代码中的 System.Reflection 命名空间来实现的。这些工具通常使用更底层的 API 或自定义的解析器来读取和理解 .NET 元数据。

10.依赖注入容器(DI Container)的简化示例,它展示了如何注册服务、解析服务和使用构造函数注入。

csharp 复制代码
using System;
using System.Collections.Concurrent;

public interface IService
{
    void DoWork();
}

public class MyService : IService
{
    public void DoWork()
    {
        Console.WriteLine("MyService is working.");
    }
}

public class DependencyContainer
{
    private readonly ConcurrentDictionary<Type, object> _services = new ConcurrentDictionary<Type, object>();

    public void Register<TService, TImplementation>()
        where TService : class
        where TImplementation : TService, new()
    {
        _services.TryAdd(typeof(TService), new TImplementation());
    }

    public TService Resolve<TService>()
        where TService : class
    {
        if (_services.TryGetValue(typeof(TService), out object service))
        {
            return (TService)service;
        }

        throw new InvalidOperationException($"No service registered for type {typeof(TService).FullName}");
    }
}

public class SomeClassThatDependsOnService
{
    private readonly IService _service;

    public SomeClassThatDependsOnService(IService service)
    {
        _service = service;
    }

    public void DoSomething()
    {
        _service.DoWork();
        Console.WriteLine("SomeClassThatDependsOnService is doing something.");
    }
}

class Program
{
    static void Main()
    {
        var container = new DependencyContainer();

        // 注册服务
        container.Register<IService, MyService>();

        // 解析服务
        IService service = container.Resolve<IService>();
        service.DoWork(); // 输出 "MyService is working."

        // 使用构造函数注入
        SomeClassThatDependsOnService dependentClass = container.Resolve<SomeClassThatDependsOnService>();
        dependentClass.DoSomething(); // 输出 "MyService is working." 和 "SomeClassThatDependsOnService is doing something."
    }
}

在这个例子中,DependencyContainer 类有两个主要方法:Register 用于注册服务,Resolve 用于解析服务。Register 方法将实现类型 TImplementation 注册为服务类型 TService 的实例。Resolve 方法则根据请求的服务类型返回相应的服务实例。

SomeClassThatDependsOnService 类展示了如何使用构造函数注入来获取依赖的服务实例。在 Main 方法中,我们首先注册服务,然后解析服务以展示其基本用法,最后通过构造函数注入来展示如何在实际应用中使用依赖注入。

相关推荐
baiduopenmap14 分钟前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
loooseFish22 分钟前
小程序webview我爱死你了 小程序webview和H5通讯
前端
广煜永不挂科33 分钟前
Devexpress.Dashboard的调用二义性
c#·express
请叫我欧皇i34 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_36 分钟前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
guokanglun42 分钟前
空间数据存储格式GeoJSON
前端
zhang-zan1 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium
猫爪笔记1 小时前
前端:HTML (学习笔记)【2】
前端·笔记·学习·html
brief of gali2 小时前
记录一个奇怪的前端布局现象
前端
Json_181790144802 小时前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库