.NET 4.5 CustomReflectionContext:它有什么用? [英] .NET 4.5 CustomReflectionContext: what is it useful for?

查看:18
本文介绍了.NET 4.5 CustomReflectionContext:它有什么用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

.NET Framework 4.5 开发者预览版的新增功能 提及

能够自定义反射上下文以覆盖默认值通过 CustomReflectionContext 的反射行为 类.

Ability to customize a reflection context to override default reflection behavior through the CustomReflectionContext class.

ReflectionContext 的目的是什么?MSDN 在这个主题上不是很清楚.

What is the purpose of the ReflectionContext? MSDN is not quite clear on the subject.

推荐答案

在过去的 .NET 中,在希望能够通过反射自动化某些功能和能够自定义它们之间一直存在紧张关系.例如,以 Visual Studio 中的属性"面板为例 - 在显示某些 .NET 类型(例如,设计图面上的控件)的场景中,它可以自动发现并显示该类型定义的每个公共属性.

In the past with .NET, there has been tension between wanting to be able to automate certain features through reflection, and being able to customize them. For example, take the Properties panel in Visual Studio - in scenarios where this shows some .NET type (e.g., a control on a design surface), it can automatically discover and display every public property that the type defines.

对这种类型驱动的行为使用反射很有用,因为这意味着控件的开发人员无需执行任何操作即可显示每个属性.但它提出了一个问题:如果你想自定义东西怎么办,例如为特定属性定义分类或自定义编辑 UI?

Using reflection for this sort of type-driven behaviour is useful because it means that every property will show up without the developer of the control needing to do anything. But it presents a problem: what if you want to customize things, e.g. defining categorization or a custom editing UI for a particular property?

.NET 中的经典解决方案是将一堆自定义属性添加到相关成员上.然而,一个问题是它可能意味着你的代码在运行时做有意义的工作的部分最终取决于只在设计时做任何事情的类 - 依赖属性阻止你分离运行时和设计时方面.您真的想将 VS 属性面板的自定义设计器 UI 的代码作为最终用户计算机上的控件库的一部分发布吗?

The classic solution in .NET is to slap a bunch of custom attributes onto the relevant members. However, one problem with that is that it can mean the parts of your code that do a meaningful job at runtime end up depending on classes that only do anything at design time - relying on attributes prevents you from separating out the runtime and design time aspects. Do you really want to ship the code for a custom designer UI for VS's properties panel as part of a control library that will end up on end user machines?

另一个问题是,在某些情况下,您可能希望动态决定您呈现的属性".最古老的例子之一(可追溯到 .NET 1.0)是将 DataSet 放入某种网格控件(客户端或 Web)中.对于强类型数据集,反射可能是网格发现源提供哪些属性的合适方式,但是 DataSet 也可以动态使用,因此您需要一种方法让数据网格询问在运行时显示哪些列.

Another problem is that in some situations you may want to decide dynamically what 'properties' you present. One of the oldest examples of this (dating back to .NET 1.0) was putting a DataSet in some sort of grid control (either client-side or web). With a strongly-typed dataset, reflection might be an appropriate way for the grid to discover which properties the source provides, but DataSet could also be used dynamically, so you need a way for the data grid to ask at runtime what columns to display.

(对此的一个答案是:正确设计你的 UI!像这样直接生成网格会导致糟糕的用户体验.然而,很多人都想以懒惰的方式来做,不管它是不是一个好主意......)

(One answer to this is: design your UI properly! Generating grids directly like this leads to horrible user experiences. However, a lot of people want to do it the lazy way, whether it's a good idea or not...)

因此,有时您需要反射驱动的行为,但有时您希望能够在运行时完全控制.

So you then have a situation where sometimes you want reflection-driven behaviour, but sometimes you want to be able to take total control at runtime.

为此出现了各种临时解决方案.您拥有整个 TypeDescriptorPropertyDescriptor 类型系列,它们在反射之上提供了一种可虚拟化的视图.默认情况下,这只会直接从反射传递所有内容,但类型有机会在运行时选择提供自定义描述符,使它们能够修改甚至完全替换它们的外观.ICustomTypeDescriptor 是那个世界的一部分.

Various ad hoc solutions emerged for this. You have the whole TypeDescriptor and PropertyDescriptor family of types, which provide a sort of virtualizable view on top of reflection. By default, this would just pass everything straight through from reflection but types have the opportunity to opt into providing custom descriptors at runtime, enabling them to modify or even completely replace how they look. ICustomTypeDescriptor is part of that world.

这为默认情况下需要反射驱动行为的问题提供了一种解决方案,如果需要,可以选择提供运行时驱动行为.但这并不能解决您只想在设计时执行此操作,并且您不想将该代码作为运行时可再发行组件的一部分发布的问题.

That provides one solution to the issue of wanting reflection-driven behaviour by default with the option to provide runtime-driven behaviour if you want it. But it doesn't solve the problem where you only want to do this at design time, and you don't want to have to ship that code as part of your runtime redistributables.

几年前,Visual Studio 引入了自己的特殊机制,用于在设计时增加类型信息.有一堆约定驱动的行为,其中 Visual Studio 将自动发现与特定运行时组件相关的设计时组件,使您能够自定义设计体验,而无需将相关代码烘焙到可再发行组件中.Blend 也使用了这种机制,但进行了一些调整,可以为 VS 和 Blend 提供不同的设计器.

So a few years ago, Visual Studio introduced its own ad hoc mechanisms for augmenting type information at design time. There's a bunch of convention-driven behaviour in which Visual Studio will automatically discover the design-time components that related to particular runtime components, enabling you to customize the design experience without needing to bake the relevant code into your redistributables. Blend also uses this mechanism, although with some tweaks, making it possible to provide different designer pieces for VS and Blend.

当然,通过普通的反射 API 看不到这些 - VS 和 Blend 有一个位于反射之上的包装层来使这一切正常工作.

Of course, none of that's visible through the normal reflection APIs - VS and Blend have a wrapper layer that sits on top of reflection to make this all work.

所以现在我们有两个虚拟化层可以传递到反射,或者可以增强反射的结果......

So now we've got two virtualization layers that can pass through to reflection, or can augment what comes out of reflection...

看起来在 .NET 4.5 中,CLR 团队决定,由于各个团队已经在做这种事情,而其他团队想要做更多的事情(MEF 团队对反射驱动具有类似的要求——可选运行时增强行为),这正是应该内置到运行时中的事情.

It looks like in .NET 4.5, the CLR team decided that since various groups were already doing this sort of thing, and other groups wanted to do more of it (the MEF team had similar requirements for reflection-driven-with-optional-runtime-augmentation behaviour), this was exactly the sort of thing that should be built into the runtime.

新模型似乎是这样的:ReflectionContext 基类是一个抽象 API,通过它您可以获得反射 API 的虚拟化版本.它看似简单,因为其中一个主要思想是,如果您的唯一目标是在反射之​​上获得可虚拟化的包装器,则您不再需要像类型描述符系统这样的专门 API——反射现在是开箱即用的虚拟化.所以你可以写这种东西

The new model seems to be this: the ReflectionContext base class is an abstract API through which you can get a virtualized version of the reflection API. It's deceptively simple, because one of the main ideas is that you no longer need specialized APIs like the type descriptor system if your only goal is to get a virtualizable wrapper on top of reflection - reflection is now virtualizable out of the box. So you can write this sort of thing

public static void ShowAllAttributes(Type t)
{
    foreach (Attribute attr in t.GetCustomAttributes(true))
    {
        Console.WriteLine(attr);
    }
}

现在您总是能够编写它,但在 .NET 4.5 之前,这样的代码将始终针对真实"类型信息工作,因为它使用反射.但是由于反射上下文,现在可以使用虚拟化的 Type 来提供它.所以考虑一下这种非常无聊的类型:

Now you've always been able to write that, but prior to .NET 4.5, code like this would always be working against 'real' type information because it uses Reflection. But thanks to reflection contexts, it's now possible to provide this with a virtualized Type. So consider this very boring type:

class NoRealAttributes
{
}

如果你只是将 typeof(NoRealAttributes) 传递给我的 ShowAllAttributes 方法,它不会打印任何内容.但是我可以写一个(有点人为的)自定义反射上下文:

If you just pass typeof(NoRealAttributes) to my ShowAllAttributes method, it will print out nothing. But I can write a (somewhat contrived) custom reflection context:

class MyReflectionContext : CustomReflectionContext
{
    protected override IEnumerable<object> GetCustomAttributes(MemberInfo member, IEnumerable<object> declaredAttributes)
    {
        if (member == typeof(NoRealAttributes))
        {
            return new[] { new DefaultMemberAttribute("Foo") };
        }
        else
        {
            return base.GetCustomAttributes(member, declaredAttributes);
        }
    }
}

(顺便说一句,我认为 CustomReflectionContext 与其基础 ReflectionContext 之间的区别在于后者定义了用于可虚拟化反射上下文的 API,而 CustomReflectionContext 添加了一些帮助程序,使您可以更轻松地实现这样的事情.)现在我可以使用它为我的类提供 Type 的虚拟化版本:

(By the way, I think the distinction between CustomReflectionContext and its base, ReflectionContext is that the latter defines the API for a virtualizable reflection context, while CustomReflectionContext adds some helpers to make it easier for you to implement such a thing.) And now I can use that to provide a virtualized version of the Type for my class:

var ctx = new MyReflectionContext();
Type mapped = ctx.MapType(typeof(NoRealAttributes).GetTypeInfo());
ShowAllAttributes(mapped);

在这段代码中,mapped 仍然指的是一个 Type 对象,所以任何知道如何使用反射 API 的人都可以使用它,但它会现在报告实际不存在的属性的存在.当然,Type 是抽象的,所以我们总是从它派生出一些东西,如果你调用 mapped.GetType() 你会看到它实际上是一个 System.Reflection.Context.Custom.CustomType 而不是您通常看到的 System.RuntimeType.而那个 CustomType 对象属于我的自定义上下文,因此您可以通过它获得任何其他反射 API 对象(例如,如果您编写了 mapped.Assembly.GetTypes())您还将获得通过我的自定义上下文的自定义对象,这将有机会修改出现的任何其他内容.

In this code, mapped still refers to a Type object, so anything that knows how to use the reflection API will be able to work with it, but it will now report the presence of an attribute that isn't actually there. Of course, Type is abstract, so we always have something that's derived from that, and if you call mapped.GetType() you'll see that it's actually a System.Reflection.Context.Custom.CustomType rather than the System.RuntimeType you'd normally see. And that CustomType object belongs to my custom context, so any other reflection API objects you get hold of through it (e.g., if you wrote mapped.Assembly.GetTypes()) you'd also get customized objects that go through my custom context, which would have the opportunity to modify anything else that comes out.

因此代码可以使用自定义的 Type 对象在类型系统中导航.尽管这些代码使用的是普通的基本反射 API,但我现在有机会自定义任何我认为合适的内容.

So code can navigate through the type system using the customized Type object. Even though such code is using the ordinary basic reflection API, I now have the opportunity to customize anything that comes out of that if I see fit.

只有在您需要时才能获得此虚拟化视图.例如,.NET 4.5 中的 MEF 查找自定义属性,指定它应该使用用户提供的自定义反射上下文,否则将回退到普通反射.(对于我的 ShowAllAttributes 方法,它使用我选择传入的任何 Type 对象 - 它不知道它是虚拟化的还是真实的"类型对象.)

You only get this virtualized view if you ask for it. For example, MEF in .NET 4.5 looks for a custom attribute specifying that it should use a user-supplied custom reflection context, but will fall back to ordinary reflection otherwise. (And in the case of my ShowAllAttributes method, it uses whatever Type object I choose to pass in - it doesn't know if it's getting a virtualized or a 'real' type object.)

简而言之,这意味着如果您想要虚拟化类型信息,您不再需要围绕反射 API 的临时包装器.

So in short, this means you no longer need ad hoc wrappers around the reflection API if you want virtualized type information.

这篇关于.NET 4.5 CustomReflectionContext:它有什么用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆