反思解决了什么问题?

时间:2009-06-24 07:41:24

标签: c# reflection

我浏览了reflection上的所有帖子,但找不到我的问题的答案。

.NET反射之前编程世界中存在哪些问题 来了,它是如何解决这些问题的?

请举例说明。

4 个答案:

答案 0 :(得分:14)

应该说.NET反射不是革命性的 - 概念已经在其他框架中出现了。

.NET中的反思有两个方面:

调查类型信息

如果没有某种反射/内省API,就很难执行序列化等操作。不是在运行时提供(通过检查属性/字段/等),而是经常需要代码生成,即明确知道如何序列化每个类型的代码。如果你想序列化没有双胞胎的东西,那就很乏味,也很痛苦。

同样,无处存储有关属性等的其他元数据,因此最终会有大量额外代码或外部配置文件。简单到能够将友好名称与属性(通过属性)相关联的东西是UI代码的巨大胜利。

<强>元编程

.NET反射还提供了一种在运行时创建类型(等)的机制,这对某些特定场景非常强大;替代方案是:

  • 本质上是在运行时运行解析器/逻辑树(而不是在运行时将逻辑编译成可执行代码) - 慢得多
  • 更多代码生成 - yay!

答案 1 :(得分:9)

我认为要了解.NET中反射的必要性,我们需要回到.NET之前。毕竟,像Java和C#这样的现代语言没有历史BF(在反射之前)。

C ++可能对C#和Java产生了最大的影响。但是C ++最初没有反射,我们编码没有它,我们设法得到了。偶尔我们有无效指针,并会使用强制转换强制它为我们想要的任何类型。这里的问题是演员阵容可能会因为可怕的后果而失败:

double CalculateSize(void* rectangle) {
    return ((Rect*)rectangle)->getWidth() * ((Rect*)rectangle)->getHeight());
}

现在有很多争论,为什么你不应该首先将自己编码到这个问题中。但是当我们没有使用泛型时,问题与使用C#的.NET 1.1没有太大区别:

Hashtable shapes = new Hashtable();
....
double CalculateSize(object shape) {
    return ((Rect)shape).Width * ((Rect)shape).Height;
}

但是,当C#示例失败时,它会使用异常而不是潜在的核心转储。

当反射被添加到C ++(称为运行时类型识别或RTTI)时,它受到了激烈的争论。在Stroustrup的“C ++的设计和演变”一书中,他列出了以下内容 反对RTTI的论点,有些人:

Declared the support unnecessary
Declared the new style inherently evil ("against the spirit of C++")
Deemed it too expensive
Thought it too complicated and confusing
Saw it as the beginning of an avalanche of new features

但它确实允许我们查询对象的类型或对象的特征。例如(使用C#)

Hashtable shapes = new Hashtable();
....
double CalculateSize(object shape) {
    if(shape is Rect) {
        return ((Rect)shape).Width * ((Rect)shape).Height;
    }
    else if(shape is Circle) {
        return Math.Power(((Circle)shape).Radius, 2.0) * Math.PI;
    }
}

当然,通过适当的规划,这个例子永远不需要发生。

因此,我需要它的真实世界情况包括:

  • 从共享内存中访问对象,我所拥有的只是一个指针,我需要决定如何处理它。
  • 动态加载程序集,考虑NUnit加载每个程序集的位置,并使用反射来确定哪些类是测试装置。
  • 在Hashtable中有一个混合的对象包并希望在枚举器中以不同方式处理它们。
  • 许多其他人......

所以,我会尽可能地认为,反思并没有能够做出以前无法做到的事情。但是,它确实使某些类型的问题更容易编码,读者更清楚,写入更短等等。

当然,这只是我的意见,我可能是错的。

答案 2 :(得分:1)

我曾经希望在文本文件中进行单元测试,可以由非技术用户以C ++格式进行修改:

MyObj Function args //textfile.txt

但我找不到一种方法来读取字符串,然后让代码创建一个由字符串表示的类型的对象实例,而不反映C ++不支持。

char *str; //read in some type from a text file say the string is "MyObj"
str *obj;  //cast a pointer as type MyObj  
obj = new str;  //create a MyObj

另一种用途可能是拥有一个通用的复制功能,可以在不事先知道的情况下复制类的成员。

答案 3 :(得分:0)

当您在代码中使用[Obsolete]或[Serializable]等C#属性时,它会有很大帮助。像NUnit这样的框架在类上使用反射并包含了解哪些方法是测试,设置,拆卸等的方法。