反射。我们可以用它来实现什么?

时间:2009-12-13 20:58:11

标签: c# reflection .net-3.5

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

感谢。

14 个答案:

答案 0 :(得分:11)

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

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,
}

使用反射获取字段:

    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
}

答案 1 :(得分:10)

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

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

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

答案 2 :(得分:3)

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

  • ORMs(物化等)
  • 序列化/反序列化
  • 对象克隆/深层复制
  • UI /绑定代码(严格这是ComponentModel,但您可以将两者混合使用 - 例如,HyperDescriptor)

您当然应该尝试尽量减少您所做的反思,但您可以通过缓存来自Delegate.CreateDelegate / Expression / DynamicMethod

的代表来降低费用

答案 3 :(得分:2)

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

答案 4 :(得分:1)

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

考虑到这一点,这不会在最终制作中出现,但在迭代阶段删除了一些模板,我需要更改。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

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

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

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

[TypeConverter(typeof(IndexedExpandableObjectConverter))]
[BinarySerializeable]
public sealed class Socket
{
    #region Fields (7) 

    [SerializedPosition(0)]
    Byte _mode = 1;

    ...

    [SerializedPositionAttribute(4)]
    UInt16 _localPort;

    ...

#地区属性(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<BinarySerializationProviderAttribute>(obj);

    if (providerAttrib != null)
        return CreateProvider(providerAttrib.ProviderType);

    return CreateProvider(typeof(SerializationProvider));
}

答案 7 :(得分:1)

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


    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");
        }
    }

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

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

Managed Extensibility Framework(一个新的.NET库)使用反射:

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

答案 10 :(得分:0)

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

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

答案 11 :(得分:0)

我将它用于:

  • 依赖注入
  • 微软的解决方法缺乏添加“covariant / contravariant generic”和“new()约束与参数”等内容的动力“
  • 面向方面编程(在某种程度上,主要是我使用PostSharp)

答案 12 :(得分:0)

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

答案 13 :(得分:-1)

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

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

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