[C# Advanced Series] [MEF Framework (1)]

C# Advanced Series

Chapter 1 [C# Advanced Series] [MEF Framework (1)]



Preface

Here is a basic introduction to MEF, including the use of a specific scenario (it should be easier for those engaged in automated operation control host computer development to substitute the scenario), and a step-by-step introduction to how to transition from common programming to framework programming development.


1. Introduction to MEF

  • MEF, the full name is Managed Extensibility Framework. MEF is a framework dedicated to solving scalability issues.
  • MSDN: Managed Extensibility Framework or MEF is a library for creating extensible, lightweight applications. Application developers can use this library to discover and use extensions without configuration. Extension developers can also leverage the library to easily encapsulate code and avoid generating brittle hard dependencies. With MEF, extensions can be reused not only within an application, but also between applications.
  • MEF (Managed Extensibility Framework) is a lightweight plug-in framework. Simple to use and powerful.
  • MEF is located in the ComponentModel.Composition assembly, add project references to System.ComponentModel.Composition and System.ComponentModel.Composition.Hosting

2. Why use MEF?

Let’s first assume a scenario: In the motion control host computer programming development, there are two types of motion control cards: Goco and Lesai. Now we need to implement different programming according to which card is used in the actual device.
Conventional implementation:

class Program
{
    
    
    static void Main(string[] args)
    {
    
    
        string ret = "";
        string cardName = "实际设备使用哪种运动控制卡";
        if (cardName == "固高板卡")
        {
    
    
            CLeadshine cLeadshine = new CLeadshine();
            ret = cLeadshine.InitMotionCard();
            ret = cLeadshine.ExitMotionCard();
        }
        else if (cardName == "雷赛板卡")
        {
    
    
            CGoogol cGoogol = new CGoogol();
            ret = cGoogol.InitMotionCard();
            ret = cGoogol.ExitMotionCard();
        }
    }
}

public class CLeadshine
{
    
    
    public string InitMotionCard()
    {
    
    
        return "初始化固高板卡成功";
    }
    public string ExitMotionCard()
    {
    
    
        return "退出固高板卡成功";
    }
}

public class CGoogol
{
    
    
    public string InitMotionCard()
    {
    
    
        return "初始化雷赛板卡成功";
    }
    public string ExitMotionCard()
    {
    
    
        return "退出雷赛板卡成功";
    }
}

After reading the above code, you can imagine that there is a main running program MEF_P1.exe, a Leadshine.dll, and a Googol.dll. The main program needs to reference two DLLs.
The above code does not use an interface, which violates the principle of dependency inversion. Next, we add an interface MotionCard.dll, so that both Leadshine.dll and Googol.dll inherit this interface to ensure the versatility and standardization of use; the code is implemented as follows
:

class Program
{
    
    
    static void Main(string[] args)
    {
    
    
        string ret = "";
        string cardName = "实际设备使用哪种运动控制卡";
        IMotionCard motionCard = null;
        if (cardName == "固高板卡")
        {
    
    
            motionCard = new CLeadshine();
        }
        else if (cardName == "雷赛板卡")
        {
    
    
            motionCard = new CGoogol();
        }
        ret = motionCard.InitMotionCard();
        ret = motionCard.ExitMotionCard();
    }
}


public interface IMotionCard
{
    
    
    string InitMotionCard();
    string ExitMotionCard();
}

public class CLeadshine : IMotionCard
{
    
    
    public string InitMotionCard()
    {
    
    
        return "初始化固高板卡成功";
    }
    public string ExitMotionCard()
    {
    
    
        return "退出固高板卡成功";
    }
}

public class CGoogol : IMotionCard
{
    
    
    public string InitMotionCard()
    {
    
    
        return "初始化雷赛板卡成功";
    }
    public string ExitMotionCard()
    {
    
    
        return "退出雷赛板卡成功";
    }
}

It can be seen that after using the interface, you only need to instantiate the interface according to different implementation classes, which is more suitable for team-assisted development;
but this is not enough. In complex system design, not only team-assisted development must be considered, but also team-assisted development must be considered. Find ways to achieve loose coupling to facilitate future expansion and other maintenance;
what if another person in the team adds a moving board?
The current practice is:
1. Add a ZMotion.dll, inherit the IMotionCard interface, and implement the specific code;
2. In the main program, reference ZMotion.dll, add the IF branch of the "positive motion board", and use CZMotion to implement the class Instantiation interface;

Next, we will introduce the concept of MEF to see how MEF operates, whether it achieves loose coupling in comparison, and what practical application advantages it has.

3. Concept of MEF

MEF (Managed Extensibility Framework) enables developers to provide hooks in their .Net applications for user and third-party extensions. Think of MEF as a universal application extension utility.
MEF enables developers to create extensions dynamically without extending the application and without requiring any knowledge specific to the extension content. This ensures that there is no coupling between the two at compile time, allowing the application to be extended at runtime without the need for recompilation.
MEF can also view the metadata of the extension assembly before loading the extension into the application, which is a faster method.
Explanation of some specific terms:
Contract: Contract, that is, an agreement.
Part: Component, that is, the implementation of the contract (added to the catalog through the Export feature)
Catalog: Catalog, where parts are stored. When a certain part is needed, it will be in the catalog Find
Container: Container, store the directory and perform component management, such as export, import, etc.
Compose: Assembly, find the components that implement the corresponding contract in the directory through the container, and assemble the components.
Export: Export, which is provided by the components to the container A value that can decorate a class, field, property, or method.
Import: Import, get the available exports from the container, and can decorate fields, properties, or constructor parameters.
ImportMany: Import multiple
DirectoryCatalog: Specify the path where the directory is located.
Lazy<T,TMetadata>: Lazy loading, a type provided by MEF to hold indirect references to exports.

4. Usage examples

Still modify it in the above scenario. We increase the application of MEF so that the main program MEF_P1.exe does not depend on Leadshine.dll and Googol.dll. Instead, it searches for DLL files in the specified path based on ContractName (contract name) to achieve the same function, thus solving the upper-level dependencies. Strong coupling problem in the lower layer.
The code structure is as follows:
main program MEF_P1.exe

class Program
{
    
    
    static string DllFilePath = "";
    static string ContractName = "";
    static void Main(string[] args)
    {
    
    
        string ret = "";
        string cardName = "实际设备使用哪种运动控制卡";
        cardName = "固高板卡";
        if (cardName == "固高板卡")
        {
    
    
            DllFilePath = "Googol.dll";
            ContractName = "GoogolCard";
        }
        else if (cardName == "雷赛板卡")
        {
    
    
            DllFilePath = "Leadshine.dll";
            ContractName = "LeadshineCard";
        }

        ret = InitMotionCard();
        ret = ExitMotionCard();
    }
    public static string InitMotionCard()
    {
    
    
        return ExportPart(ContractName, DllFilePath).InitMotionCard();
    }
    public static string ExitMotionCard()
    {
    
    
        return ExportPart(ContractName, DllFilePath).ExitMotionCard();
    }

    public static IMotionCard ExportPart(string ContractName, string DllName)
    {
    
    
        // 创建一个程序集目录,用于从一个程序集获取所有的组件定义
        //Assembly.GetExecutingAssembly():当前方法所在程序集
        //Assembly.GetCallingAssembly():调用当前方法的方法 所在的程序集
        //Assembly.LoadFrom(@"DLLName.dll"):DLLName.dll的程序集
        AssemblyCatalog Catalog = new AssemblyCatalog(Assembly.LoadFrom(DllName));
        //创建容器
        CompositionContainer Container = new CompositionContainer(Catalog);
        //获得容器中的Export
        IMotionCard Export = Container.GetExportedValue<IMotionCard>(ContractName);
        return Export;
    }
}

InterfaceMotionCard.dll

public interface IMotionCard
{
    
    
    string InitMotionCard();
    string ExitMotionCard();
}

Plug-inGoogol.dll

[Export("GoogolCard", typeof(IMotionCard))]
public class CGoogol : IMotionCard
{
    
    
    public string InitMotionCard()
    {
    
    
        return "初始化固高板卡成功";
    }
    public string ExitMotionCard()
    {
    
    
        return "退出固高板卡成功";
    }
}

Plug-inLeadshine.dll

[Export("LeadshineCard", typeof(IMotionCard))]
public class CLeadshine : IMotionCard
{
    
    
    public string InitMotionCard()
    {
    
    
        return "初始化雷赛板卡成功";
    }
    public string ExitMotionCard()
    {
    
    
        return "退出雷赛板卡成功";
    }
}

In this way, how to operate when you need to add a positive moving board?
1. Add a ZMotion.dll, inherit the IMotionCard interface, and implement the specific code;
2. In the main program, add the protocol name and DLL path of the "positive motion board";
done? Not yet, we still need to modify the main program at this time, which is not what we want, but at this step, the effect is already obvious. Next,
we will strip the contract name and DLL name from the program into the configuration file, and design a visual interface Just provide new additions and modifications. In
this way, how to operate when you need to add a positive motion board?
1. Add a ZMotion.dll, inherit the IMotionCard interface, and implement the specific code;
2. Change the configuration file or change the configuration on the visual interface
. This way there is no need to change the code of MEF_P1.exe or recompile. ZMotion.dll is equivalent to a plug-in, only It can be loaded into the application by changing the configuration file.

The final effect is as shown below. When you need to add ZMotion.dll, write ZMotion.dll and put it in the specified path, modify the config.xml configuration file, add Item3 information, and then open the software directly, and the positive motion will appear in the software drop-down box. The board is stuck, you can select the operation.
Insert image description here

5. Benefits of MEF framework

decoupling

Just imagine, if the main program references Leadshine.dll and Googol.dll, it means that you can have unlimited access to classes, properties, and methods in the DLL, which means that there will be a lot of coupled code in the main program. , one day you want to remove this DLL, the program will definitely fail to compile, and you will have to manually delete these coupling codes. Since MEF completes the call through the intermediate interface, it only exposes the members in the interface. The programmer is Any method in the DLL cannot be called arbitrarily, it can only be called through the interface. Even if this DLL is deleted, the program can still run normally!

Scalability

For example, suppose your program has been handed over to the customer, and one day the customer says that he no longer wants to use the Googol or Lesain boards and wants to use the positive motion board. At this time, you only need to re-create ZMotion. dll, making it inherit and implement the IMotionCard interface. Then, as long as ZMotion.dll and the modified configuration file are handed over to the customer, and let them modify the selected options, they can run and use the positive motion board. Isn’t it very convenient! If it were in the past, you would have to modify the code of the main program, then recompile, publish, and then hand over the entire program to the customer. Everyone should understand this!

More

MEF can not only export classes, but also export methods and properties, whether private or public, to meet more needs!

6. Source code link

MEF plug-in framework learning display (source code) (1)

Summarize

Dependency Inversion Principle: High-level templates should not depend on low-level templates, both should depend on abstractions, and abstractions should not depend on details.

Guess you like

Origin blog.csdn.net/Aflashstar/article/details/129063647