.NET 中的元数据是啥?

Posted

技术标签:

【中文标题】.NET 中的元数据是啥?【英文标题】:What is metadata in .NET?.NET 中的元数据是什么? 【发布时间】:2012-02-10 06:37:19 【问题描述】:

我搜索了几个网站以了解 metadata 在 .NET 中的含义。

我还是 C# WPF 桌面应用程序编程的新手。回到我做网络编程的时候,html 代码中有元标记,我们用标题、关键字等来描述网站。 .NET 应用程序中也类似吗?我阅读了 wiki,并在 Google 上搜索过,但我得到的只是概念性解释。

一个描述"metadata is data that describes the state of the assembly and a detailed description of each type, attribute within the assembly"。元数据只是一个概念还是像我在某处输入的代码行来描述我的代码的物理内容?如果是这样,我的推荐会成为我的元数据吗?

我读到的元数据是"Within the Common Language Runtime (CLR)",但我只用C#编码,如何在CLR中编码到元数据中?元数据是 CLR 中的一个推荐吗?我该如何改变它。

MSDN 写道,元数据是另一种语言的软件组件理解它的二进制信息。我虽然只有人类需要用英语描述(推荐)来理解代码块的作用。软件组件简单地执行我们编写的任何语句——“二进制”信息的需要是什么。编译器如何理解我生成“程序集描述”的高级代码的含义?如果我编写一个转换货币的程序,元数据会在知道程序正在转换货币的情况下自动生成吗?这种情报在哪里?

我完全糊涂了。

【问题讨论】:

【参考方案1】:

元数据是源代码本身信息的一部分,在编译时存储在程序集的特殊部分中。它实际上是程序集结构的实现细节。对于典型的 C# 应用程序开发,您实际上并不需要了解这一点。如果您开发开发人员工具,这主要是相关的。

“元数据”一词有些误导。程序集元数据包括代码中的内容,例如常量和字符串文字,这不是通常意义上的元数据。更正确的术语可能是不可执行的数据。

当 C# 编译成程序集时,编译输出分为两个部分。 IL 是字节码格式的实际可执行代码,而“元数据”是所有其他内容:类型、接口和成员声明、方法签名、常量、外部依赖项等。

参加这个程序:

class Program

    public static void Main(string[] args)
    
        var x = 2 + 2;
        Console.WriteLine("Hello World!");
    

当这个程序被编译成程序集时,它被分成元数据和 IL。 元数据包含这些声明(以独立于语言的二进制格式表示):

class Program

    public static void Main(string[] args);

此外,元数据还包含字符串文字"Hello World!",以及程序集在mscorlib.dll 中引用System.Console.WriteLine 的信息。

只有这部分被编译成 IL:

var x = 2 + 2;
Console.WriteLine("Hello World!");

需要注意的是,方法引用和文字字符串在 IL 中表示为指向元数据的指针。另一方面,元数据中的方法声明具有指向 IL 的指针,指向实现方法体的代码。

因此,它归结为一种将可执行​​(命令式)IL 代码与不可执行(声明性)部分分开的方法。

为什么这种分离有用?因为它允许工具提取和使用元数据,而无需实际执行任何 IL。例如,Visual Studio 只需读取元数据即可为程序集中定义的成员提供代码补全。编译器可以检查从其他程序集调用的方法是否确实存在以及参数是否匹配等等。

【讨论】:

【参考方案2】:

不要把它复杂化,它只是---关于数据的数据(信息)。

想想 HTML 中的 Meta 标签,它包含关于页面、关键字、作者、最后修改的信息。这意味着它包含有关您的 html 页面的数据的信息。

当我们谈论 C# 时, 元数据存储在 .NET Framework 可移植可执行 (PE) 文件的一个部分中,而 Microsoft 中间语言 (MSIL) 存储在 PE 文件的另一部分中。文件的元数据部分包含一系列表和堆数据结构。 MSIL 部分包含引用 PE 文件的元数据部分的 MSIL 和元数据令牌。 每个元数据表都包含有关程序元素的信息。例如,一个元数据表描述代码中的类,另一个表描述字段,等等。如果您的代码中有十个类,则类表将有十行,每个类一个。元数据表引用其他表和堆。例如,类的元数据表引用方法的表。 元数据还将信息存储在四种堆结构中:字符串、blob、用户字符串和 GUID。所有用于命名类型和成员的字符串都存储在字符串堆中。例如,方法表不直接存储特定方法的名称,而是指向存储在字符串堆中的方法名称。

如果这让你感兴趣的话--https://msdn.microsoft.com/en-us/library/xcd8txaw%28v=vs.110%29.aspx

【讨论】:

【参考方案3】:

由于其他人已经提供了很好的解释性答案,我只提一下如何自己查看元数据。

在您的 Microsoft SDK 目录(很可能是 C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools 的变体)中有一个名为 ildasm.exe 的程序 - 很简单允许您查看已编译的 .NET 二进制文件的反汇编程序。

您可以构建非常简单的控制台应用程序并使用ildasm.exe 来查看编译后的内容。 View/MetaInfo/Show! 命令(或简单地 Ctrl + M)将显示元数据 - 您可以检查它们的外观。从应用打印Hello到控制台的部分元数据:

TypeDef #1 (02000002)
-------------------------------------------------------
TypDefName: Program  (02000002)
Flags     : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit](00100001)
Extends   : 01000001 [TypeRef] System.Object
Method #1 (06000001) [ENTRYPOINT]
-------------------------------------------------------
    MethodName: Main (06000001)
    Flags     : [Public] [Static] [HideBySig] [ReuseSlot]  (00000096)
    RVA       : 0x00002050
    ImplFlags : [IL] [Managed]  (00000000)
    CallCnvntn: [DEFAULT]
    ReturnType: Void
    1 Arguments
        Argument #1:  SZArray String
    1 Parameters
        (1) ParamToken : (08000001) Name : args flags: [none] (00000000)

在这里您可以看到类型定义 (Program) 及其方法之一 (Main),它采用单个输入参数并返回 void。这自然只是元数据的一部分,即使是最简单的程序也有很多。

【讨论】:

+1 我必须将此作为我的答案,因为它使阅读其他答案变得有意义并消除我的困惑。【参考方案4】:

如果您熟悉 .NET 反射,您可以将元数据视为“反射访问的数据”。每个 .NET 程序集都存储有关它包含的类型和方法、这些方法的属性等信息。它不需要存储这些信息只是为了运行代码(本机 EXE 没有那种信息),但它需要它用于其他目的,例如强制声明式安全和启用反射。

所以元数据是“物理的”,但其中大部分是由您编写的代码自动生成的。向您的类或方法添加属性可能是您可以直接更改元数据的唯一方法。特别是,您的源代码 cmets 不会作为元数据(或以任何其他方式)存储在程序集中。

这方面的***页面非常好:http://en.wikipedia.org/wiki/.NET_metadata

编辑:不,元数据不像 cmets。它只是“关于代码的数据”,它不是代码本身的一部分(不需要运行程序)。它根本不像 HTML 元数据。元数据的一个例子是程序集包含一个名为“MyClass”的类,并且该类包含一个名为“DoSomething”的方法,带有某些参数等。所以这并不神秘 - 主要是“明显”的东西。

【讨论】:

我读了维基,我很困惑。元数据应该像推荐一样描述我的代码吗?计算机如何理解我的目的并为我生成它?在 HTML 中,使用关键字和标题手动输入元标记来描述页面,浏览器不够智能,无法理解页面内容并为我生成关键字和标题?伙计,我都很困惑.. 所以元数据捕获类、方法、变量等的标识符。这有什么意义?获取标识符名称 = 描述我的数据吗?我虽然方法签名也总结了方法中的信息..再次,更加困惑。对不起。请帮忙 对,方法签名是元数据的一部分。只需调用该方法,就足以知道该方法的二进制偏移量及其参数的数量和大小。但是,.NET 存储完整的签名:方法名称、返回类型、每个参数的确切类型和名称、方法或参数的任何属性等。这就是元数据。它的重点是启用反射(和其他一些东西)。【参考方案5】:

简单地说,元数据是存储在您的程序中的信息,您可以通过多种方式对其进行检查,在 .NET 中,其中一种方法通常称为反射

元数据描述类型(例如类、接口等)、方法和参数(名称和类型)以及已应用的属性。您可以通过多种方式使用此信息,例如nunit 和 msstest 等测试系统(以及其他系统)使用元数据“发现”程序集中的测试;可以使用元数据的其他方式是数据绑定。

有很多方法可以使用它 - 他们甚至有关于它的书籍(至少有部分http://my.safaribooksonline.com/book/programming/csharp/9781449379629/reflection-and-metadata/729)

【讨论】:

如果我有一个方法“myMethod”,元数据将如何描述它?编译器不知道方法是什么意思,只执行,除了自己手动输入,怎么生成描述?困惑。 没错,元数据就是类型名、方法名、参数名、局部变量名……等信息。 查看ILSpy 以了解用于解释 IL 并返回“等效”源代码的元数据。【参考方案6】:

这篇is a great and comprehensive关于点网元数据的文章。看看它。我希望它能清除很多东西。它有一个链接到解释how meta data is used at runtime的页面。

dot net 中的Reflection 是一个非常强大的概念,它基于reading the metadata 与实际代码一起存储。

【讨论】:

以上是关于.NET 中的元数据是啥?的主要内容,如果未能解决你的问题,请参考以下文章

对本身位于元组中的元组(可迭代的可迭代)求和的最有效方法是啥?

我的元组中的那些小“u”是啥? (python 2.7)[重复]

使用 C# 从 ASP.Net MVC 中的视频文件中获取视频元数据的最佳方法是啥?

计算中常说的元表是啥?

编程里面元组和数组的区别是啥?

类型提示存储为clojure中的元数据?