C# Resources资源详解
1. Resource Basics (1) Manifest Resources(资源清单) 资源在编译期间添加到程序集。如果要将资源嵌入到程序集,则必须将文件添加到项目中,文件会自动拷贝到项目文件夹的Resources文件夹中。如果要嵌入到程序集,还需选中文件,修改其属性“生成操作”(Build Action)为“嵌入的资源”,默认为“内容”。 一旦设置为嵌入的资源,则它就会成为资源清单中程序集的一部分。每一程序集,无论是静态的还是动态的,均包含描述该程序集中各元素彼此如何关联的数据集合。程序集清单就包含这些程序集元数据。程序集清单包含指定该程序集的版本要求和安全标识所需的所有元数据,以及定义该程序集的范围和解析对资源和类的引用所需的全部元数据。 (2) Naming Mainfest Resources 要查看一个已经正确嵌入到项目输出程序集中的文件,可以利用SDK工具 ildasm.exe,它其实就是 MSIL 反汇编程序,它能够在你程序集的Mainfest视图里显示所有的嵌入资源。 它在ildasm中显示为 .mresource 入口,资源名称显示格式如下: defaultNamespace.folderName.fileName defaultNamespace 可以在项目的属性页面中“应用程序”Tab页面中进行更改。 (3) Loading Mainfest Resources 也通过程序来枚举清单,需要利用到 System.Reflection.Assembly 类的 GetMainifestResourceNames 方法。另外,还可以检索特定类型的程序集,例如 Assembly 类还提供了 GetAssembly、GetCallingAssembly、GetEntryAssembly 和 GetExecutingAssembly 等。 // Get this type's assembly Assembly asm =this.GetType().Assembly; // Enumerate the assembly's manifest resources foreach( string resourceName in asm.GetManifestResourceNames() ){ MessageBox.Show(resourceName); } Type 为 System.Reflection 功能的根,也是访问元数据的主要方式。使用 Type 的成员获取关于类型声明的信息,如构造函数、方法、字段、属性 (Property) 和类的事件,以及在其中部署该类的模块和程序集。 表示某个类型是唯一的 Type 对象;即,两个 Type 对象引用当且仅当它们表示相同的类型时,才引用相同的对象。这允许使用参考等式来比较 Type 对象。Type 类表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。Object.GetType 方法返回表示实例类型的 Type 对象。 如果知道资源的名称,则可以通过 Assembly 类的方法 GetManifestResourceStream 方法加载指定的清单资源,资源名称大小写敏感,而且是全称。例如: // Get this type's assembly Assembly asm =this.GetType().Assembly; // Get the stream that holds the resource // from the "ResourcesSample.Azul.jpg" resource // NOTE1: Make sure not to close this stream,// or the Bitmap object will lose access to it // NOTE2: Also be very careful to match the case // on the resource name itself Stream stream = asm.GetManifestResourceStream("ResourcesSample.Azul.jpg"); // Load the bitmap from the stream this.BackgroundImage =new Bitmap(stream); (4) Mainfest Resource Namespaces 如果传递给 GetMainfestResourcesStream 方法 一个System.Type 对象,则它会用此类型的命名空间当作嵌入资源的前缀的一部分,如: // Load the stream for resource "ResourcesSample.Azul.jpg" Stream stream = asm.GetManifestResourceStream(this.GetType(),"Azul.jpg"); Bitmap 类也可以直接装载嵌入的资源,如: // Load image from "ResourcesApp.Azul.jpg" this.BackgroundImage =new Bitmap(this.GetType(),"Azul.jpg"); 2. Strongly Typed Resources 在清单资源中不包含类型信息,虽然文件带有扩展名,但是类似Bitmap类是根据数据本身来判断类型的。 (1) Application Resources(.resx) Files 资源文件(.resx)的主要作用就是记录资源的相应类型信息,由于采用了.NET特定的XML方案(ResX)来保存资源类型信息。一个空的 .resx 文件也有42行内容,大多数都是方案信息。这个方案允许有许多条目信息,每个都包含name、value,comment,type 和 Multipurpose Internet Mail Extensions(MIME) type。虽然此文件是基于文本的,但是如果要编辑或者阅读,最好还是通过VS2005的资源编辑器来完成。 .resx 格式中的名称/值对在 XML 代码中打包,它描述字符串或对象值。当字符串被添加到 .resx 文件中时,该字符串的名称被嵌入在 <data> 标记中,并且值包括在 <value> 标记内,如以下示例所示。 (2) Managing Resources 资源编辑器支持六类资源: a. 字符串 : 在带有字符串资源的“名称”、“值”和“注释”列的设置网格中显示字符串。 添加资源: 可以通过拖放、菜单选择来添加资源,通过资源编辑器添加到.resx文件的所有资源文件都会放到项目文件夹下的Resources文件夹下,如果不存在则创建。如果将一个已经存在项目里的资源添加到.resx文件中,则这个资源不会被移动或拷贝到Resources文件夹下,因为资源编辑器是通过对文件的引用来管理资源文件,resx文件仅仅存放实际清单资源的类型信息。 删除资源: 通过资源编辑器只能从.resx中移除或者剪切资源,而不能实际删除,因为你只是对资源的元数据进行操作,而并非真正的资源文件(字符串除外,它只能被嵌入)。如果从项目中删除资源文件,但是.resx中的相应元数据还在,这样在编译时就会出现编译异常。 编辑资源: 可以通过资源编辑器直接打开相应的编辑程序; (3) Resource Persistance 链接资源作为文件存储在项目中;在编译期间,从这些文件中取得资源数据,并将其放到应用程序的清单中。应用程序的资源文件 (.resx) 只存储指向磁盘上的文件的相对路径或链接。对于嵌入资源,资源数据直接以二进制数据的文本表示形式存储在 .resx 文件中。在任何一种情况下,资源数据都将编译到可执行文件中。 注意点:字符串资源总是嵌入的资源,无法更改;文件资源总是链接的资源,也无法更改。 如何在嵌入的资源和链接的资源之间进行选择? 嵌入的资源: 链接的资源: 可以通过指定资源的Persistance属性来决定。如果将属性改为嵌入后,将资源文件删除并不会有什么影响,此时如果再改回链接方式,则会在Resources目录下重新创建此资源文件。 如果在资源编辑器下对资源进行管理,则会发现资源的BuildAction,即生成操作都会变为“无”。其实Persistance属性仅仅在设计期间起作用,最终资源数据都将编译到可执行文件中。 (4) Using Typed Resources * 直接使用.resx文件 利用 ResXResourceReader 类来访问.resx 文件; using( ResXResourceReader reader = new ResXResourceReader(@"C:MyResources.resx") ) { foreach( DictionaryEntry entry in reader ) { string s =string.Format("{0} ({1})= '{2}'",entry.Key,entry.Value.GetType(),entry.Value); MessageBox.Show(s); } } * 使用编译的.resx 资源 您可以采用三种不同的方式创建资源文件。如果您的资源将只包含字符串数据,则最简单的方法是手动创建文本文件。如果您的资源将包含对象或字符串与对象的组合,则您必须创建 .resx 文件或 .resources 文件。只有.resources 文件才应嵌入在公共语言运行库程序集和附属程序集中。资源文件生成器 (Resgen.exe) 将文本 (.txt) 文件和基于 XML 的资源 (.resx) 文件转换成 .resources 文件, 资源生成器 Resgen.exe : 编译项目后会将.resx数据嵌入为嵌套资源放在资源清单,例如项目缺省命名空间为A,rest文件为B.resx,则这个嵌套资源容器则为 A.B.resources,可以在ildasm中查看。对它的读取利用 ResourceReader 类,也不支持随机访问。 using( ResourceReader reader = new ResourceReader("MyResources.resources") ) { foreach( DictionaryEntry entry in reader ) { string s =string.Format("{0} ({1})= '{2}'",entry.Value); MessageBox.Show(s); } } 其实还可以直接通过对清单资源流的访问来操作 .resources 文件。 Assembly asm = Assembly.GetExecutingAssembly(); // Load embedded .resources file using( Stream stream = asm.GetManifestResourceStream( this.GetType(),"MyResources.resources") ) { // Find resource in .resources stream using( ResourceReader reader =new ResourceReader(stream) ) { foreach( DictionaryEntry entry in reader ) { if( entry.Key.ToString() =="MyString" ) { // Display string resource value MessageBox.Show("MyString = "+ (string)entry.Value); break; } } } } 以上都需要进行多步操作而且不支持随机访问,但是.NET提供了 ResourceManager 类来支持对资源的随机访问。 (5) Resource Manager ResourceManager 类可以查找区域性特定的资源,当本地化资源不存在时提供代用资源,并支持资源序列化,它其实也就是对ResourceReader的封装。它由一个嵌入.resource文件初始化: Assembly asm =this.GetType().Assembly; ResourceManager resman =new ResourceManager("ResourcesSample.MyResources",asm); 通过 ResourceManager 的方法,调用方可使用 GetObject 和 GetString 两种方法访问特定区域性的资源。 // Load ResourcesSample.MainForm.resources from MainForm.resx ResourceManager resman =new ResourceManager(this.GetType()); // Access the MyString string resource from the ResourceManager // (these two techniques are equivalent for strings) string s1 = (string)resman.GetObject("MyString"); string s2 = resman.GetString("MyString"); (6) 强类型资源类 Resource Manager 提供了对资源的弱类型方法GetObject来返回资源,需要进行类型转换。但是VS2005和一个自定义工具 ResXFileCodeGenerator 提供了对这个问题的解决办法。当一个 .resx 文件被保存时,VS2005会应用自定义工具将其产生一个相应的 .Designer.cs 文件,此文件提供了一个名字和 .resx 文件相同的类,这个类所处的命名空间为 defaultNamespace.projectPath。 namespace ResourcesSample { ///<summary> /// A strongly typed resource class,for looking up localized /// strings,etc. ///</summary> // This class was autogenerated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member,edit your .resx file and then rerun ResGen // with the /str option,or rebuild your VS project. internalclass MyResources { static global::System.Resources.ResourceManager resourceMan; static global::System.Globalization.CultureInfo resourceCulture; internal MyResources() {} ///<summary> /// Returns the cached ResourceManager instance used by this /// class. ///</summary> internalstatic global:: System.Resources.ResourceManager ResourceManager { get { if( (resourceMan ==null) ) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager( "ResourcesSample.MyResources",typeof(MyResources).Assembly); resourceMan = temp; } return resourceMan; } } ///<summary> /// Overrides the current thread's CurrentUICulture property for /// all resource lookups using this strongly typed resource class. ///</summary> internalstatic global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } } } 由以上可以看出 MyResource 类型的两个特征: a. 它通过一个ResourceManager类型的属性提供了对ResourceManager的静态访问,就没必要写之前的创建逻辑了; b. 通过一个Culture属性提供了CultureInfo对象实现对本地化信息的静态访问; 提供的每个资源都是强类型静态只读属性。在内部实现中,每个属性都由设计器生成的资源类利用托管的ResourceMananger对象产生的; // Access strongly typed resources from MyResources.resx string myString = MyResources.MyString; Icon myIcon = MyResources.MyIcon; (7) Designer Resources VS2005提供了整个项目的资源管理。由于Resources.resx 文件是从项目的属性页来进行管理的,所以 VS2005将它存放到项目的Properties文件夹中。当在项目中添加.resx文件时,ResXFileCodeGenerator工具会自动生成Resources.Designer.cs: namespace ResourcesSample.Properties { 则可以如下来访问资源:MessageBox.Show(Properties.Resources.MyString); 项目会自动生成一个跟窗体关联的.resx 文件,保存类似 BackgroundImage 和 Icon 等资源信息。属性窗口可以打开选择资源编辑器,允许选择适当的图片资源。它提供了两种导入和保存资源的方式:作为本地资源;作为项目资源文件。对于窗体,本地资源被嵌入到窗体设计器自动创建的.resx文件中并和窗体关联,如果选择本地资源,则可以直接将图片导入到窗体的资源文件中。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |