reflection。 我们可以用它做什么?

我正在阅读和学习C#中的reflection。 很高兴知道它在我的日常工作中如何帮助我,所以我希望有比我更多经验的人告诉我关于我们可以使用它做什么样的事情的样本或想法,或者我们如何减少代码量我们写的。

谢谢。

我最近用它来为我的枚举中的字段添加自定义属性:

public enum ShapeName { // Lines [ShapeDescription(ShapeType.Line, "Horizontal Scroll Distance", "The horizontal distance to scroll the browser in order to center the game.")] HorizontalScrollBar, [ShapeDescription(ShapeType.Line, "Vertical Scroll Distance", "The vertical distance to scroll the browser in order to center the game.")] VerticalScrollBar, } 

使用reflection获取字段:

  public static ShapeDescriptionAttribute GetShapeDescription(this ShapeName shapeName) { Type type = shapeName.GetType(); FieldInfo fieldInfo = type.GetField(shapeName.ToString()); ShapeDescriptionAttribute[] attribs = fieldInfo.GetCustomAttributes(typeof(ShapeDescriptionAttribute), false) as ShapeDescriptionAttribute[]; return (attribs != null && attribs.Length > 0) ? attribs[0] : new ShapeDescriptionAttribute(ShapeType.NotSet, shapeName.ToString()); } 

属性类:

 [AttributeUsage(AttributeTargets.Field)] public class ShapeDescriptionAttribute: Attribute { #region Constructor public ShapeDescriptionAttribute(ShapeType shapeType, string name) : this(shapeType, name, name) { } public ShapeDescriptionAttribute(ShapeType shapeType, string name, string description) { Description = description; Name = name; Type = shapeType; } #endregion #region Public Properties public string Description { get; protected set; } public string Name { get; protected set; } public ShapeType Type { get; protected set; } #endregion } 

一般而言,Reflection允许您访问有关对象的元数据。 将Reflection与其他技术相结合,可以使您的程序更具动态性。 例如,您可以加载DLL并确定它是否包含接口的实现。 您可以使用它来发现运行时支持function的dll。 使用它可以使用它来扩展应用程序而无需重新编译,也无需重新启动它。

Visual Studio中的Intellisense使用reflection为您提供有关您正在使用的对象的信息。

请注意,使用Reflection需要付出代价。 reflection物体可能很慢。 但如果你需要它,Reflection是一个非常有用的工具。

对于没有任何需要了解调用者的库代码来说,这是非常宝贵的 – 比如generics,但对数据的访问更丰富。 例子:

  • ORM(物化等)
  • 序列化/反序列化
  • 对象克隆/深层复制
  • UI /绑定代码( 严格来说这是ComponentModel,但你可以混合两者 – 例如,HyperDescriptor)

您当然应该尽量减少您所做的reflection量,但是您可以通过从Delegate.CreateDelegate / Expression / DynamicMethod缓存Delegate.CreateDelegate来降低成本

其中一个用途是:您可以创建一个插件体系结构,在其中指定配置文件中要使用的类的名称。 使用reflection,您可以获取此字符串并创建所请求对象的实例。 如果该对象实现了已知接口,则可以通过普通(非reflection)代码使用它。

我使用reflection让我更灵活地满足不断变化的要求。 也就是说,客户不断改变他们在数据库中放置数据库表的位置。 我所做的只是让对象自我检查它的字段并调用对象本身内的那些字段的对象构造函数。 那么,如果在其他地方找到一张桌子? 点击,粘贴,完成。

请注意,这在最终生产中没有出现,但在迭代阶段,我需要更改一些样板。

我使用reflection来促进表格上标签和按钮等控件的转换。 使用reflection,我将遍历表单上的所有控件,并将控件名称,文本和标题写入XML文件。 在XML中翻译控件标题和文​​本后,将XML中的每个控件的标题和文本设置为其翻译值,即可读回该文件。
我们的表格需要翻译成几种不同的语言,使用reflection帮助我们节省了大量时间。

VS中的属性窗口是基于reflection的 – 如果您创建用户控件,则可以立即从PropertyGrid (它也是您可以使用的控件)修改其上的任何属性。 当然,您可以添加属性以增强其显示方式(通过reflection访问)。

我也用它来实现自定义二进制序列化类。

在这里,我有一个类,我使用reflection来序列化/反序列化它 – 并提供其他UI信息的属性。

 [TypeConverter(typeof(IndexedExpandableObjectConverter))] [BinarySerializeable] public sealed class Socket { #region Fields (7) [SerializedPosition(0)] Byte _mode = 1; ... [SerializedPositionAttribute(4)] UInt16 _localPort; ... 

#region属性(5)

  [DisplayName("Listning Port")] [Description("The port which the socket will listen for connections on")] [DisplayIndex (0)] public UInt16 LocalPort { get { return _localPort; } set { _localPort = value; } } ... 

和序列化函数 – 正如您所看到的,它只需要一个对象和您想要的字节顺序(字节顺序)。 其他一切都是由反思决定的。 默认的SerializationProvider使用对象内的字段上的SerializedPosition属性(私有或非私有)。

 public static Byte[] Serialize(Object obj, ByteOrder streamOrder) { var provider = GetProvider(obj); if (provider.CanSerialize(obj.GetType())) return provider.Serialize(obj, streamOrder); throw new ArgumentException(obj.GetType() + " is non-serialisable by the specified provider '" + provider.GetType().FullName + "'."); } private static IBinarySerializatoinProvider GetProvider(Object obj) { var providerAttrib = Reflector.GetAttribute(obj); if (providerAttrib != null) return CreateProvider(providerAttrib.ProviderType); return CreateProvider(typeof(SerializationProvider)); } 

这是基于枚举或魔术字符串执行方法的方法……

 public enum ReflectionTestMethods { MethodA, MethodB, MethodC } public class ReflectionTest { public void Execute(ReflectionTestMethods method) { MethodInfo methodInfo = GetType().GetMethod(method.ToString() , BindingFlags.Instance | BindingFlags.NonPublic); if (methodInfo == null) throw new NotImplementedException(method.ToString()); methodInfo.Invoke(this, null); } private void MethodA() { Debug.Print("MethodA"); } private void MethodB() { Debug.Print("MethodB"); } private void MethodC() { Debug.Print("MethodC"); } } 

但这可能是一个更好的解决方案……

 public class ActionTest { private readonly Dictionary _actions = new Dictionary(); public ActionTest() { _actions.Add(ReflectionTestMethods.MethodA.ToString(), new Action(MethodA)); _actions.Add(ReflectionTestMethods.MethodB.ToString(), new Action(MethodB)); _actions.Add(ReflectionTestMethods.MethodC.ToString(), new Action(MethodC)); } public void Execute(ReflectionTestMethods method) { if (!_actions.ContainsKey(method.ToString())) throw new NotImplementedException(method.ToString()); _actions[method.ToString()](); } private void MethodA() { Debug.Print("MethodA"); } private void MethodB() { Debug.Print("MethodB"); } private void MethodC() { Debug.Print("MethodC"); } } 

我只在生产代码中使用过一次reflection。 在这种情况下,我不得不调整什么 – 在那个时间点 – 在启动例程中标准化使用特定类方法(抱歉不要更具说明性 – 它是在不久之前,细节是朦胧)。 解决问题的唯一方法是引入不同版本的方法,并在运行时检查各种标准/代码条件等,以确定我应该调用哪种方法。 这是一段非常紧凑的代码,它提供了一个解决方案来解决本来可能解决的混乱问题。

以下是我使用过的一些反思,如果没有它,这将是非常困难或不可能的:

  • 我的StringTemplate模板引擎的C#端口。 reflection用于检索动态对象的属性。
  • 用托管代码编写的CLI JIT编译器。

Managed Extensibility Framework (一个新的.NET库)使用reflection来:

  • 找到并撰写零件,包括应用Imports。
  • 它避免在需要内容之前加载程序集以供执行。

我想这是一个“独立”的应用程序,你在编译时知道你使用的每个对象,你不会使用很多reflection。

但是当您编写应该在编译时使用未知对象(完全 – 您可能知道接口或基类)的库或框架代码时,reflection对于处理这些对象可能是非常宝贵的。

我用它来:

  • dependency injection
  • 微软的变通办法缺乏添加诸如“协变/逆变通用”和“新()约束与参数”之类的东西的动机“
  • 面向方面编程(在某种程度上,我主要使用PostSharp)

反思很适合“后期绑定”解决方案,在这种解决方案中,您不希望将物理参考连接到项目,而是稍后“连接”它。 这样,如果引用不存在并且不重要,则不会发现缺少引用的未处理错误。 您会收到可以处理的受控错误。

我使用Red Gate .Net Reflector来更好地理解.Net框架本身的机制。 曾经想知道特定框架对象是如何或为什么以它的方式工作,或者你曾经有点难过为什么某些东西不能以你认为的方式工作?

有时文档可能有点简陋,但至少可以通过使用reflection和Redgate的工具,你可以在框架代码中嗅探,以更好地理解它的方式/原因/内容。

通过“MS局外人”使用reflection在CLR代码中发现了一些错误。