首页 > 解决方案 > 何时使用反射而不是引用程序集

问题描述

我在 .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#dllreflection.net-assembly

解决方案


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

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

        // 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是什么,我们都会使用反射来找出它的公共属性是什么。然后我们将使用这些属性来获取每个项目的相应值。

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


推荐阅读