C # Study Notes on scalable programming (5): MEF advanced
I haven't written a blog for a long time. Today I am taking the time to write more articles in the MEF series. Some Garden Friends proposed that this series of articles should be made a directory that looks convenient, so they took the time to make one and put it at the end of each article. In the previous four articles, we talked about the basic knowledge of MEF. After completing the first four articles, we have already finished the basics that are commonly used in MEF. I believe you can see the convenience brought by MEF. Today, we will introduce some of the more uncommon features of MEF, that is, the so-called relatively advanced usage in the audience. The Export mentioned above adds the Export annotation to each class to implement Export. Is there a simple method? The answer is yes. It is to write an annotation on the interface, so that all classes that implement this interface will be exported without the need to write an annotation on each class. Below, only the source code of the interface and one implementation class is pasted, and the rest can be imitated: The interface code is as follows: copy the code using System; using System. collections. generic; using System. linq; using System. text; using System. componentModel. composition; namespace BankInterface {[InheritedExport] public interface ICard {// account amount double Money {get; set ;}// obtain account information string GetCountInfo (); // save void SaveMoney (double money); // void CheckOutMoney (double money);} added the [InheritedExport] Mark on the copy code Interface Yes. This is the annotation used on the interface. The following is an implementation class code: copy the code using System; using System. collections. generic; using System. linq; using System. text; using BankInterface; using System. componentModel. composition; namespace BankOfChina {// [Export (typeof (ICard)] public class ZHCard: ICard {public string GetCountInfo () {return "Bank Of China ";} public void SaveMoney (double money) {this. money + = money;} public void CheckOutMoney (double money ){ This. money-= money;} public double Money {get; set ;}} copy the code and you can see that I have commented out the exported annotation, this class is still exported, and the running result is believed to have been read from the previous article. Note: although this method is relatively simple, it is only applicable to relatively simple applications. After reading the following content, I believe everyone will be aware of its shortcomings. Next, we will focus on how to access a specific object in MEF. We have discussed how to add a name identifier to the [Export ()] annotation during Export, to identify a specific object. However, this method is only used for filtering during page initialization. Once the page is opened, it cannot be imported any more, that is to say, we cannot distinguish the differences in the import set. All imported classes are not identified. To add an identifier for each class, we need to inherit the ExportAttribute class and add the MetaData attribute for it. First, we need to write the class inherited from ExportAttribute. The Code is as follows: copy the code using System; using System. collections. generic; using System. linq; using System. text; using System. componentModel. composition; namespace BankInterface {// <summary> // AllowMultiple = false, this attribute cannot be used many times for a class. // </summary> [MetadataAttribute] [AttributeUsage (AttributeTargets. class, AllowMultiple = false)] public clas S exportcardattriattribute: ExportAttribute {public ExportCardAttribute (): base (typeof (ICard) {} public string CardType {get; set ;}} copying the code is simple, the constructor of the parent class called declares a CatdType attribute. Next, add an interface and directly modify the ICard interface file. The Code is as follows: copy the code using System; using System. collections. generic; using System. linq; using System. text; using System. componentModel. composition; namespace BankInterface {public interface ICard {// account amount double Money {Get; set ;}// get account information string GetCountInfo (); // save void SaveMoney (double money); // get the money void CheckOutMoney (double money );} public interface IMetaData {string CardType {get ;}} copied the code and added the interface IMetaData. There is only one attribute. Note that this attribute must be consistent with the attribute name in the newly written ExportCardAttribute class, in this way, you can export data. The following uses our ExportCardAttribute attribute to mark the class we want to export: copy the code using System; using System. collections. generic; using System. linq; using System. text; using BankInterface; using System. componentModel. composition; namespace BankOfChina {[ExportCardAttribute (CardType = "BankOfChina")] public class ZHCard: ICard {public string GetCountInfo () {return "Bank Of China ";} public void SaveMoney (double money) {this. money + = money ;} Public void CheckOutMoney (double money) {this. money-= money;} public double Money {get; set ;}} copy the code here. We can set the CardType attribute and use different data types according to the actual situation. Now, we modify the main program code to: copy the code using System; using System. collections. generic; using System. linq; using System. text; using System. reflection; using System. componentModel. composition; using System. componentModel. composition. hosting; using BankInterface; namespace MEFDemo {class Program {// The AllowRecomposition = true parameter indicates that the component set is restructured after the new component is assembled successfully. [importtables (AllowRecomposition = true)] public IEnumerable <Lazy <ICard, IMet AData> cards {get; set;} static void Main (string [] args) {Program pro = new Program (); pro. compose (); foreach (var c in pro. cards) {if (c. metadata. cardType = "BankOfChina") {Console. writeLine ("Here is a card of Bank Of China"); Console. writeLine (c. value. getCountInfo ();} if (c. metadata. cardType = "NongHang") {Console. writeLine ("Here is a card of Nong Ye Yin Hang"); Console. writeLine (c. Value. getCountInfo ();} Console. read ();} private void Compose () {var catiner = new DirectoryCatalog ("Cards"); var container = new CompositionContainer (catalog); container. composeParts (this) ;}} copy the code. Here I use the Lazy delayed loading mechanism (For details, refer to Lazy delayed loading). We can see that we can access the CardType Attribute Based on the MetaData attribute, in this way, the Card type is determined to distinguish the import type.