使用/需要反思

时间:2012-12-27 11:25:14

标签: c# .net reflection

我在这个论坛上搜索过这些问题并找到了很好的资源。我自己编写了以下代码来理解反射的概念。

static void Main(String[] args)
    {

        MyClass1 mc1 = new MyClass1();
        Type t = mc1.GetType();
        MethodInfo mInfo = t.GetMethod("method1");
        object[] o=new object[]{2};
        Console.WriteLine(mInfo.Invoke(mc1, o));
        NameSpace2.Class1 c1 = new NameSpace2.Class1();
        Type t2 = c1.GetType();
        MethodInfo[] mI2 = t2.GetMethods();
        object[] o2 = new object[] {2,3};
        foreach (MethodInfo m in mI2)
        {
            Console.WriteLine(m);
        }

        object x = Activator.CreateInstance(t);

        Console.WriteLine(x.GetType());
        Console.Read();

    }

我理解通过反射,我将能够在运行时获取有关类型,公共方法,对象属性的信息,并且还能够创建该类型的对象。但我的观点是,除非我知道方法需要什么参数作为输入,否则我将无法实现任何方法,并且这些信息仅在运行时可用。那么,反思的重要性是什么,它只是关于对象的信息吗?

3 个答案:

答案 0 :(得分:3)

如果您需要反思,那么您的需求无法在编译时解决,而是在运行时解决。

  • 假设您正在制作一个需要模块化的酷应用程序,您可以让开发人员为您的应用程序编写插件。 您无法为可能创建的每个插件编译应用程序。然后,您需要加载,内省并使用反射调用插件的对象。

  • 假设您正在为银行应用程序制作中间件,该中间件负责处理数据库连接并使用该数据执行某些业务逻辑。您可以为每个可用的数据库编写和编译中间件。或者您可以编写一次代码,并在运行时激活并使用正确的数据库驱动程序。

  • 如果您希望动态获取WebService的WSDL,生成代理并在编译代理后立即使用Web服务并加载到内存中,该怎么办?想不出在编译时这样做的方法。

  • 更好的是,如果使用CodeDOM生成代码,编译,加载已编译的程序集并使用刚刚编译的对象,该怎么办?

有一天你需要使用反射。我希望如此......

答案 1 :(得分:1)

除了 Adrian Salazar 的回答之外,我还有一些我去年面临的例子:

  • 自动生成包装器。我编写了一个使用OpenGL / OpenAL的跨平台框架,为了保持简单,我使用了在设备可用后初始化的委托。在iOS上,我需要使用dll-import属性将每个方法声明为extern方法。 OpenGL / OpenAL有很多方法,所以我只编译了代理,编写了一个程序,它写了一个* .cs文件,声明了所有的theese方法。现在,这保护了我一周的痛苦工作,让这个包装纸保持最新状态。
  • 代理生成。我曾经写过一个应用程序,它必须能够处理Flash对象并在PropertyInspector中显示它们的属性并调用对象的方法,才能做到这一点,我写了一个IL-generator并使用反射来反映属性并调用方法。
  • 最常见的示例应该是:加载并保存数据。此任务主要通过使用反射来完成。我在2012年中期编写了一个xml-reader / writer,它允许像在XAML中那样初始化对象,并再次将这些对象保存到XML中。对象初始化并将它们再次写回XML是一项任务,如果您不使用反射,这将导致大量工作。

正如您所看到的,有很多例子证明反射确实很有用。在过去的8年里,我多次使用反射,我甚至无法计算使用次数。

答案 2 :(得分:0)

说出你的隐含问题。

  

但我的观点是,除非我知道方法需要哪些参数作为输入,否则我将无法实现任何方法,并且这些信息仅在运行时可用。

我们举一个简单的例子。我想在一个需要参数的类上实例化一个方法,我将成为辅导员(即我将创建该类并启动该方法,但我对此一无所知)。

public class Foo
{
    public Foo() { }

    public void FooMethod(string parm) { }
}

public class Facilitator
{
    public void RaiseAction(string type, string action, params object[] parm)
    {
        var o = Activator.CreateInstance("MyAssembly", type);
        var methodInfo = o.GetType().GetMethod(action);
        if (methodInfo == null) { return; }
        methodInfo.Invoke(o, parm);
    }
}

现在,在上面的例子中,我只是将参数传递给我一无所知的对象上的方法。

现在,让我们来研究一下使用Reflection可能实现的其他一些事情。让我们想象一下,我需要找到一个private成员 - 尽管通常是一个坏主意 - 如果有必要我可以做,我有时会调试 黑客攻击你有没有想过一个在运行时无法帮助你做出决定的旗帜?您在调试器中看到了该标志,但它隐藏在对象层次结构 中,它是private来启动!更糟糕的是?微软表示,他们将在后续版本中以某种方式公开它,但你需要立即出门,你需要这个标志!或许你需要这种方法!

考虑这个例子(其中o是某些对象,你需要私有的东西):

var propertyInfo = o.GetType().GetProperty("SomePublicProperty");
if (propertyInfo == null) { return; }
var myFirstPrivateMember = propertyInfo.PropertyType.GetField("_somePrivateField", BindingFlags.Instance | BindingFlags.NonPublic);

哦,我们刚刚得到了我们的第一个private成员 - 而且还有一个领域!

反思是我的心脏,因为我已经构建了许多完全动态的应用程序,从数据库一直到用户体验。当您构建类似的应用程序时,您不了解任何内容 - 您没有配置它 - 但由于反射的灵活性,您可以InvokeGet任何您想要或需要获得的内容完成的工作。

就像其他任何东西一样,这些是 非常 反射的简单例子,但希望你能够很好地理解反射的力量以及为什么它有用。在你的世界非常静止的大多数日常应用中,你可能永远都不会使用它,而是分支出来并获得更多动态,你需要它。