【问题标题】:When to use reflection instead of referencing an assembly何时使用反射而不是引用程序集
【发布时间】:2019-05-07 16:33:39
【问题描述】:

我在 .NET Framework 中创建了一个 dll,现在在另一个项目中使用它。我找到了两种使用我的 dll 的方法。

  1. 通过在我的项目引用中引用 dll 并创建实例

  2. 使用反射

我的 DLL

namespace MathHelper
{
    public class Helper
    {
        public int add(int a, int b)
        {
            return a + b;
        }
    }
}

我的程序

static void Main(string[] args)
        {
            //Using referenced dll in project
            Helper helper = new Helper();
            Console.WriteLine(helper.add(4,5));

            //Using Reflection
            Assembly assembly = Assembly.LoadFile(@"C:\Users\myUser\source\repos\TestMathHelper\TestMathHelper\bin\Debug\MathHelper.dll");
            Type type = assembly.GetType("MathHelper.Helper");
            object instance = Activator.CreateInstance(type);
            MethodInfo method = type.GetMethod("add");
            int result = (int)method.Invoke(instance, new object[] {4, 5});
            Console.WriteLine(result);

            Console.ReadKey();
        }

两个结果都有效并显示 9.

我应该更喜欢哪种方法? 什么时候应该使用反射,什么时候不应该? 反射的优点是什么?

【问题讨论】:

  • 经验法则:仅当其他更简单(和/或更快)的方法不可行时才使用反射。永远记住:你的目标应该是编写可读、可维护的代码。自己提问并回答:您在问题中概述的两种方法中的哪一种会产生更好的可读性和更好的可维护性源代码? (顺便说一句,可维护性不仅包括未来对源代码的扩展/修改,还包括调试和故障排除代码的能力/简单性)
  • 哪种方法更方便,代码更少?看起来这是第一个 - 参考。

标签: c# dll reflection .net-assembly


【解决方案1】:

如果可能的话,我们想编写类型安全的代码,编译器会告诉我们我们是否调用了一个实际存在的方法,我们是否传递了正确的参数等。如果出现问题,这样就可以了代码甚至无法编译,我们甚至在尝试运行代码之前就发现了问题。

用反射查看代码,这里有一些可能出错的地方。在每种情况下,如果我们使用引用的程序集和强类型对象和方法,编译器都会捕捉到这一点并警告我们。使用反射可以编译代码,但在运行程序之前我们不会发现问题:

        // The assembly might not be there. Or we can't load it.
        Assembly assembly = Assembly.LoadFile(@"C:\Users\myUser\source\repos\TestMathHelper\TestMathHelper\bin\Debug\MathHelper.dll");  

        // The assembly doesn't have a type with that name.
        Type type = assembly.GetType("MathHelper.Helper");

        // The type doesn't have a constructor with no arguments.
        object instance = Activator.CreateInstance(type);

        // The type doesn't have a method called "add".
        MethodInfo method = type.GetMethod("add");

        // The "add" method doesn't take two ints as arguments or doesn't return an int.
        int result = (int)method.Invoke(instance, new object[] {4, 5});

更不用说对于我们或接下来的开发人员而言,能够键入类名并让我们的 IDE 建议方法和属性的名称真是太棒了。否则,我们每次都必须查看其他类的源代码或文档,以了解它的成员是什么、它需要什么参数、这些参数的含义以及它的返回值。

在特定类型未知且不那么重要的情况下,反射通常会更好。

例如,我们可以编写一个采用List<T> 的方法,其中T 是某个对象,然后它读取每个实例的所有公共属性并将它们全部写入一个CSV 文件。

public void WriteToCsv<T>(IEnumerable<T> items, StreamWriter writer)

在这种情况下,我们不会编写处理特定类型的方法。我们并不关心类型是什么。无论T 是什么,我们都会使用反射来找出它的公共属性是什么。然后我们将使用这些属性来获取每个项目的相应值。

这是一个过度概括。使用反射有很多有效的案例。我们应该避免的是在处理已知类型时使用它,并且有一种方法可以在没有反射的情况下做我们想做的事情。如果我们把自己画到一个角落,看起来我们需要使用反射,那么也许我们可以修复部分设计。或者,如果我们认为我们需要反思,我们可以得到另一双眼睛。我之所以这么说,是因为虽然反射很有用,但它在很多不必要的情况下被使用,并且使代码更脆弱、更难理解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多