当前位置:网站首页>. Net basic knowledge quick pass 10

. Net basic knowledge quick pass 10

2022-06-09 12:32:00 Phil Arist

1 The basic principle of reflection

Reflection is a Dynamically analyze assemblies 、 modular 、 Mechanisms for target objects such as types and fields , Its implementation relies on metadata .

Metadata , It's the data that describes the data .

stay CLR in , Metadata is a description system of everything defined or referenced by a module .

2.NET How to implement reflection in

stay .NET in , It provides us with a wealth of types that can be used to implement reflection , Most of these types are defined in System.Reflection Under the namespace , for example Assembly、Module etc. . Utilize these types , We can easily dynamically load assemblies 、 modular 、 type 、 Elements such as methods and fields .

Let's take a look at an example , The first is to create an assembly SimpleAssembly, One of the classes is SimpleClass:​​​​​​

[Serializable]
public class SimpleClass
{
    private String _MyString;
    public SimpleClass(String mystring)
    {
        _MyString = mystring;
    }

    public override string ToString()
    {
        return _MyString;
    }

    static void Main(string[] args)
    {
        Console.WriteLine(" Simple assembly ");
        Console.Read();
    }
}
 The second is to analyze the modules in the assembly , Use reflection on assemblies, respectively 、 Modules and classes :​​​​​​​

public class AnalyseHelper
{
    /// <summary>
    ///  Parse assembly 
    /// </summary>
    public static void AnalyzeAssembly(Assembly assembly)
    {
        Console.WriteLine(" Assembly name :" + assembly.FullName);
        Console.WriteLine(" Assembly location :" + assembly.Location);
        Console.WriteLine(" Whether the assembly is in GAC in :" +
                    assembly.GlobalAssemblyCache.ToString());
        Console.WriteLine(" Contains the module name of the assembly " +
            assembly.ManifestModule.Name);
        Console.WriteLine(" Required to run the assembly CLR edition :" +
            assembly.ImageRuntimeVersion);
        Console.WriteLine(" Now start analyzing the modules in the assembly ");
        Module[] modules = assembly.GetModules();
        foreach (Module module in modules)
        {
            AnalyzeModule(module);
        }
    }

    /// <summary>
    ///  Analysis module 
    /// </summary>
    public static void AnalyzeModule(Module module)
    {
        Console.WriteLine(" Module name :" + module.Name);
        Console.WriteLine(" Modular UUID:" + module.ModuleVersionId);
        Console.WriteLine(" Start analyzing the types under the module ");
        Type[] types = module.GetTypes();
        foreach (Type type in types)
        {
            AnalyzeType(type);
        }
    }

    /// <summary>
    ///  Analysis type 
    /// </summary>
    public static void AnalyzeType(Type type)
    {
        Console.WriteLine(" Type name :" + type.Name);
        Console.WriteLine(" The category of type is :" + type.Attributes);
        if (type.BaseType != null)
            Console.WriteLine(" The base class of type is :" + type.BaseType.Name);
        Console.WriteLine(" Type of GUID yes :" + type.GUID);
        // Set type members of interest 
        BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
        // Analyze members 
        FieldInfo[] fields = type.GetFields(flags);
        if (fields.Length > 0)
        {
            //Console.WriteLine(" Start analyzing members of type ");
            foreach (FieldInfo field in fields)
            {
                //  Analyze members 
            }
        }
        // Analyze the included methods 
        MethodInfo[] methods = type.GetMethods(flags);
        if (methods.Length > 0)
        {
            //Console.WriteLine(" Start analyzing methods of types ");
            foreach (MethodInfo method in methods)
            {
                //  Analysis method 
            }
        }
        // Analysis properties 
        PropertyInfo[] properties = type.GetProperties(flags);
        if (properties.Length > 0)
        {
            //Console.WriteLine(" Start analyzing properties of type ");
            foreach (PropertyInfo property in properties)
            {
                //  Analysis properties 
            }
        }
    }
}

Finally, write an entry method to try to analyze a specific assembly :​​​​​​

[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public class Program
{
    public static void Main(string[] args)
    {
        Assembly assembly = Assembly.LoadFrom(@"..\..\..\SimpleAssembly\bin\Debug\SimpleAssembly.exe");
        AnalyseHelper.AnalyzeAssembly(assembly);

        //  Create an object of type in an assembly 
        Console.WriteLine(" Using reflection to create objects ");
        string[] paras = { " Test the reflection effect " };
        object obj = assembly.CreateInstance(assembly.GetModules()[0].GetTypes()[0].ToString(), true, BindingFlags.CreateInstance, null, paras, null, null);
        Console.WriteLine(obj);

        Console.ReadKey();
    }
}

The code above follows Assembly -> modular -> type Three levels of order to dynamically analyze an assembly , Of course, you can continue to recurse the members inside the type , Finally through CreateInstance Method to dynamically create a type , These are the functions that reflection is often used to accomplish , The execution result is shown in the figure below :

3 How to use reflection to implement factory mode

Factory pattern is a common design pattern , The basic idea is to use different factory types to build components of different products . for example , When we were building a room , Windows may be required 、 roof 、 door 、 roof beam 、 Columns and other parts . Some houses need many pillars , And some rooms don't need windows . Under such a demand , You can use factory mode .

(1) The traditional realization of factory mode and its disadvantages

The following figure shows the architecture of the traditional factory model designed for the house :

The design idea of the above figure is :

① The user tells the factory manager which product parts are needed ;

② The factory manager analyzes the incoming information from users , Generate appropriate type objects that implement the factory interface ;

③ Through the factory to produce the corresponding products , Return to the user a type object that implements the product interface ;

Through the above ideas , The implementation code is as follows :

① The first is to define the factory interface , Enumeration of product interfaces and product types ​​​​​​​

/// <summary>
///  Parts of house products 
/// </summary>
public enum RoomParts
{
    Roof,
    Window,
    Pillar
}

/// <summary>
///  Factory interface 
/// </summary>
public interface IFactory
{
    IProduct Produce();
}

/// <summary>
///  Product interface 
/// </summary>
public interface IProduct
{
    string GetName();
}

② The second is the product class that implements the product interface : The window 、 Roofs and columns ​​​​​​​

/// <summary>
///  roof 
/// </summary>
public class Roof : IProduct
{
    //  Implementation interface , Return product name 
    public string GetName()
    {
        return " roof ";
    }
}

/// <summary>
///  The window 
/// </summary>
public class Window : IProduct
{
    //  Implementation interface , Return product name 
    public string GetName()
    {
        return " The window ";
    }
}

/// <summary>
///  column 
/// </summary>
public class Pillar : IProduct
{
    //  Implementation interface , Return product name 
    public string GetName()
    {
        return " column ";
    }
}

③ Then there is the factory class that implements the factory interface : The implementation interface returns a specific product object ​​​​​​​

/// <summary>
///  Roof factory 
/// </summary>
public class RoofFactory : IFactory
{
    //  Implementation interface , Return a product object 
    public IProduct Produce()
    {
        return new Roof();
    }
}

/// <summary>
///  Window factory 
/// </summary>
public class WindowFactory : IFactory
{
    //  Implementation interface , Return a product object 
    public IProduct Produce()
    {
        return new Window();
    }
}

/// <summary>
///  Column factory 
/// </summary>
public class PillarFactory : IFactory
{
    //  Implementation interface , Return a product object 
    public IProduct Produce()
    {
        return new Pillar();
    }
}

④ Finally, factory management : Organize many products and factories ​​​​​​​

/// <summary>
///  Plant managers 
/// </summary>
public class FactoryManager
{
    public static IProduct GetProduct(RoomParts part)
    {
        IFactory factory = null;
        //  Disadvantages of the traditional factory mode : Tight coupling between factory management class and factory class family 
        switch (part)
        {
            case RoomParts.Roof:
                factory = new RoofFactory();
                break;
            case RoomParts.Window:
                factory = new WindowFactory();
                break;
            case RoomParts.Pillar:
                factory = new PillarFactory();
                break;
            default:
                return null;
        }

        //  Use the factory to produce products 
        IProduct product = factory.Produce();
        Console.WriteLine(" Produced a product :{0}", product.GetName());

        return product;
    }
}

According to international practice , Let's implement an entry method to test :​​​​​​​

public class Customer
{
    public static void Main(string[] args)
    {
        //  Obtain different product parts as required 
        IProduct window = FactoryManager.GetProduct(RoomParts.Window);
        Console.WriteLine(" I got it {0}",window.GetName());
        IProduct roof = FactoryManager.GetProduct(RoomParts.Roof);
        Console.WriteLine(" I got it {0}", roof.GetName());
        IProduct pillar = FactoryManager.GetProduct(RoomParts.Pillar);
        Console.WriteLine(" I got it {0}", pillar.GetName());

        Console.ReadKey();
    }
}

stay Customer Class , We have obtained different product parts according to different part types through factory management , The operation result is shown in the figure below :

When a new product — When the floor needs to be added , What we need to change is : Add part enumeration record 、 Add factory class for floor 、 Add a new flooring product class , Modify the factory management class ( stay switch Add a case sentence ), The advantage of this design is that no matter what part is added , Product users don't need to care about internal changes , As always, you can use the factory management class to get the desired parts , The disadvantages are as follows :

① Factory management class and factory class family are coupled ;

② Each time you add a new part, you need to add a pair of factory classes and product classes , There will be more and more types ;

(2) Implementation of reflection based factory pattern

Using reflection mechanism can realize more flexible factory pattern , This is reflected in the use of reflection to dynamically know which components a product is composed of , Instead of using a switch Statement to find the right factory one by one .

① product 、 Enumeration is consistent with the above , The main change here is the addition of two custom features , These two features will be attached to the product type and product interface respectively :​​​​​​​

/// <summary>
///  This feature is used to attach to the product type 
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ProductAttribute : Attribute
{
    //  Annotate members of the part 
    private RoomParts myRoomPart;

    public ProductAttribute(RoomParts part)
    {
        myRoomPart = part;
    }

    public RoomParts RoomPart
    {
        get
        {
            return myRoomPart;
        }
    }
}

/// <summary>
///  This feature is used to attach to the product interface type 
/// </summary>
[AttributeUsage(AttributeTargets.Interface)]
public class ProductListAttribute : Attribute
{
    //  Product type collection 
    private Type[] myList;

    public ProductListAttribute(Type[] products)
    {
        myList = products;
    }

    public Type[] ProductList
    {
        get
        {
            return myList;
        }
    }
}

② The following is the definition of product interface and product class family , The product interface uses ProductListAttribute characteristic , And every product uses ProductAttribute characteristic :​​​​​​​

/// <summary>
///  Product interface 
/// </summary>
[ProductList(new Type[] { typeof(Roof), typeof(Window), typeof(Pillar) })]
public interface IProduct
{
    string GetName();
}

/// <summary>
///  roof 
/// </summary>
[Product(RoomParts.Roof)]
public class Roof : IProduct
{
    //  Implementation interface , Return product name 
    public string GetName()
    {
        return " The Little Swan roof ";
    }
}

/// <summary>
///  The window 
/// </summary>
[Product(RoomParts.Window)]
public class Window : IProduct
{
    //  Implementation interface , Return product name 
    public string GetName()
    {
        return " Shuanghui window ";
    }
}

/// <summary>
///  column 
/// </summary>
[Product(RoomParts.Pillar)]
public class Pillar : IProduct
{
    //  Implementation interface , Return product name 
    public string GetName()
    {
        return " Millet pillar ";
    }
}

③ The following is the modified factory class , Due to the use of reflection properties , Here one factory type can produce all the products :​​​​​​​

/// <summary>
///  Factory 
/// </summary>
public class Factory
{
    public IProduct Produce(RoomParts part)
    {
        //  From... By reflection IProduct Interface to get a list of all products 
        ProductListAttribute attr = (ProductListAttribute)Attribute.GetCustomAttribute(typeof(IProduct), typeof(ProductListAttribute));
        //  Traverse all implementation product part types 
        foreach (var type in attr.ProductList)
        {
            //  Use reflection to find its properties 
            ProductAttribute pa = (ProductAttribute)Attribute.GetCustomAttribute(type, typeof(ProductAttribute));
            //  Determine whether it is a required part 
            if(pa.RoomPart == part)
            {
                //  Use reflection to dynamically create instances of product part types 
                object product = Assembly.GetExecutingAssembly().CreateInstance(type.FullName);
                return product as IProduct;
            }
        }

        return null;
    }
}

④ Finally, the modified factory management class , The core has only three lines of code :​​​​​​​

/// <summary>
///  Plant managers 
/// </summary>
public class FactoryManager
{
    public static IProduct GetProduct(RoomParts part)
    {
        //  There is only one factory 
        Factory factory = new Factory();
        IProduct product = factory.Produce(part);
        Console.WriteLine(" Produced a product :{0}", product.GetName());
        return product;
    }
}

The main changes in the above code are two points :

First, the factory management class no longer needs to find different factories according to different parts , Because only one factory is responsible for handling all product parts ;

The second is that the product type and product interface apply two user-defined features , To facilitate factory reflection .ProductAttribute Attached to the product category , It indicates which product part the current type represents . and ProductListAttribute Is attached to the product interface , It is convenient to know how many product parts there are .

When you need to add a new floor product part type , What we need to do is : Add part enumeration record , Add a type that represents the floor , Modification added in IProduct Property initialization parameters on ( Add floor type ), You can see that the caller 、 Both the factory management class and the factory no longer need to make changes to the newly added parts , The program only needs to add the necessary types and enumeration records .

Of course , This design also has some defects : Reflection is relatively inefficient , When there are relatively many product parts , Every time a product is produced, reflection traversal is required, which is a very time-consuming work .

End summary

This paper summarizes and reviews .NET Reflection of (Reflection) Relevant important knowledge points , The next one will summarize .NET Medium characteristics (Attribute) Relevant important knowledge points , Welcome to continue to pay attention !

原网站

版权声明
本文为[Phil Arist]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/160/202206091142062850.html