为什么在.NET中推荐使用反射?

66

它绝对是使用的良好实践吗?

在项目中,有哪些可能需要反射的情况?


本文提供了一个示例,说明如何使用反射来改进您的代码:https://levelup.gitconnected.com/write-dry-code-using-reflection-e4b9bd8581ea - David Klempfner
9个回答

47
Reflection的主要价值在于它可以用来检查程序集(assemblies)、类型(types)和成员(members)。它是一个非常强大的工具,可以用于确定未知程序集或对象的内容,并且可以在各种情况下使用。
反对Reflection的人会说它很慢,这是与静态代码执行相比确实如此。然而,Reflection在整个.NET框架中都被广泛地使用,只要不滥用,它可以成为工具箱中非常强大的工具。
一些有用的应用程序包括:
- 确定程序集的依赖项(dependencies) - 查找符合某个接口(interface)、从基类/抽象类(derive)派生的类型,以及按属性(attribute)搜索成员 - (略显臭味的)测试 - 如果你依赖于一个无法进行易于构建的伪造(fakes)的类,可以使用Reflection在类中注入假值--虽然不太美观,也不推荐,但在紧急情况下可以是一个方便的工具。 - 调试 - 输出已加载程序集的列表、它们的引用、当前方法等...

28
几乎所有的测试框架都会使用反射来开始,以查找并执行测试... - Jon Skeet

37

反射有很多用途:

  1. 遍历对象中的属性。
  2. 调用在运行时定义的方法。
  3. 还有许多其他类似的用途。

然而,我最喜欢使用反射来查找已标记属性的属性之一。

例如,我编写了标记我的类中应使用Lucene索引的属性的属性。在运行时,我可以查看任何类,并通过查询“标记”属性来确定哪些字段需要进行索引。


27

反射是一种在运行时检查对象的方法。如果您不需要这样做,就不应该使用它。


2
确实。Reflection 是一种非常强大的资源,但它需要承担性能责任,因此除非真正必要,否则不应使用。 - Konamiman
1
@Konamiman:我非常赞同,就是这么简单。此外,反射经常被滥用,而一个更简单和更好规划的架构可以轻松解决相同问题,并且具有更好的性能。 - sɐunıɔןɐqɐp

14

反射允许应用程序收集有关自身的信息并对其进行操作。它可以用于查找程序集中的所有类型和/或在程序集中动态调用方法。

System.Reflection:命名空间包含提供已加载类型、方法和字段的托管视图的类和接口,并具有动态创建和调用类型的能力,这个过程被称为.NET框架中的反射。

System.Type:类是.NET反射功能的主要类,也是访问元数据的主要途径。System.Type类是一个抽象类,表示公共类型系统(CLS)中的类型。

它代表类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义以及开放或关闭构造的泛型类型。

例如:

using System;
using System.Reflection;

static class ReflectionTest
{
    public static int Height;
    public static int Width;
    public static int Weight;
    public static string Name;

    public static void Write()
    {
    Type type = typeof(ReflectionTest); // Get type pointer
    FieldInfo[] fields = type.GetFields(); // Obtain all fields
    foreach (var field in fields) // Loop through fields
    {
        string name = field.Name; // Get string name
        object temp = field.GetValue(null); // Get value
        if (temp is int) // See if it is an integer.
        {
        int value = (int)temp;
        Console.Write(name);
        Console.Write(" (int) = ");
        Console.WriteLine(value);
        }
        else if (temp is string) // See if it is a string.
        {
        string value = temp as string;
        Console.Write(name);
        Console.Write(" (string) = ");
        Console.WriteLine(value);
        }
    }
    }
}

class Program
{
    static void Main()
    {
    ReflectionTest.Height = 100; // Set value
    ReflectionTest.Width = 50; // Set value
    ReflectionTest.Weight = 300; // Set value
    ReflectionTest.Name = "ShekharShete"; // Set value
    ReflectionTest.Write(); // Invoke reflection methods
    }
}

Output

Height (int) = 100
Width (int) = 50
Weight (int) = 300
Name (string) = ShekharShete

我仍然不明白你为什么使用它。如果可能的话,请给一个简短的描述,这将有助于我更好地理解它。谢谢。 - Rajan Mishra
常规类型系统不应该是 CTS 而不是 CLS 吗? - David Klempfner

10
你可以使用反射来实现插件系统。例如,你可以查找文件夹中的所有DLL,并通过反射检查它们是否实现了特定的插件接口。这是我使用反射的主要目的,但我还使用它来实现通用的自制对象序列化,其中性能不是最重要的考虑因素。

7

如上所述,性能会受到影响。

另一个巨大的优势是可以动态加载程序集,在没有看到要更改的内容的情况下执行属性操作等。

使用这种方法的原因有很多。如果需要,可以参考这篇介绍


7

反射在IoC容器中经常被使用。假设你想要注册所有以单词“Controller”结尾的具体类,反射可以轻松实现。

我也曾经在单元测试类时使用反射来操作私有字段。


2
非常有用的XmlSerialization类依赖于反射。您不必自己处理反射以使用序列化,序列化类会自行调用反射。但是,在代码中打上指导对象如何序列化的属性标记会有所帮助。序列化类在运行时使用反射来读取这些属性。最终,这个过程似乎几乎是神奇的,在应用程序中只需要非常少量的显式编码;正是反射使这种便利成为可能。
XmlSerialization本身之所以很棒,不仅因为它是从应用程序创建数据文件的非常方便的方法,而且还是生成可供调试目的查看程序内部数据模型的人类可读记录的非常简单的工具。

0

作为一个来自C++的程序员,我必须说is关键字是非常宝贵的,特别是在需要一些简单的类层次结构时。

class MenuItem : Item { }

foreach(Item items in parent.ChildItems) {
    if (item is MenuItem) { /* handle differently */ }
}

顺便说一句,反射是不是有点贵啊?


4
这不是反映。 :)而且,只有在某些使用情况下的特定部分才会变慢。 - leppie
我的错,这是类型内省。 - Nick Bedford
C++ 具有类型内省功能,可以执行相同的操作。 - user90843

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接