C# für Fortgeschrittene – ausführliche Erläuterung der Funktionen

C# Advanced – Detaillierte Funktionen

Null, Artikelverzeichnis

1. Was sind die Merkmale?

1. Charakteristische Definition

**Attribute** sind deklarative Tags, die zur Übermittlung von Verhaltensinformationen zu verschiedenen Elementen im Programm (z. B. Klassen, Methoden, Strukturen, Aufzählungen, Komponenten usw.) zur Laufzeit verwendet werden. Mithilfe von Attributen können Sie Ihrem Programm deklarative Informationen hinzufügen. Ein deklaratives Tag wird durch eckige Klammern ([ ]) beschrieben, die vor dem Element stehen, für das es gilt.

Das Attribut wird zum Hinzufügen von Metadaten wie Compileranweisungen und -kommentaren, Beschreibungen, Methoden, Klassen und anderen Informationen verwendet. Das .Net-Framework bietet zwei Arten von Funktionen: VordefinierteFunktionen und Benutzerdefiniert Eigenschaften.

2. Syntax der Funktionen

Name und Wert eines Attributs werden in eckigen Klammern vor dem Element angegeben, für das es gilt. positional_parameters gibt erforderliche Informationen an, name_parameter gibt optionale Informationen an.

[attribute(positional_parameters, name_parameter = value, ...)]
element

3. Was ist der Unterschied zwischen Features und Anmerkungen?

Die Funktion ist sehr leistungsstark. Nach dem Hinzufügen der Funktion verfügt sie über sehr leistungsstarke Funktionen
[Veraltet] Beim Kompilieren wird eine Eingabeaufforderung angezeigt, die sich auf den Compiler auswirkt [Veraltet(" Bitte verwenden Sie dies nicht. Bitte verwenden Sie stattdessen etwas“, true)], da sonst ein Kompilierungsfehler verursacht wird
[Serialisierbares] Objekt kann serialisiert werden, was Auswirkungen auf den Programmbetrieb hat

using System;

namespace MyAttribute
{
    /// <summary>
    /// 这里是注释,除了让人看懂这里写的是什么,对运行没有任何影响
    /// </summary>
    ///[Obsolete("请不要使用这个了,请使用什么来代替")]//对编译都产生了影响,编译出现警告
    ///[Obsolete("请不要使用这个了,请使用什么来代替", true)]//对编译都产生了影响,编译报错不通过
    [Serializable]//可以序列化和反序列化
    public class Student
    {        
        public int Id { get; set; }
        
        public string Name { get; set; }
        
        public void Study()
        {
            Console.WriteLine($"这里是{this.Name}在学习");
        }
        
        public string Answer([Custom]string name)
        {
            return $"This is {name}";
        }
    }
}

Überall Funktionen: EF–MVC–WCF–WebService–UnitTest–IOC–AOP–SuperSocket

2. Funktionsdeklaration und -verwendung

1. Was sind Merkmale?

Ein Attribut ist eigentlich eine Klasse, die direkt oder indirekt von Attribute geerbt wird

#region 程序集 mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\mscorlib.dll
// Decompiled with ICSharpCode.Decompiler 6.1.0.5902
#endregion

using System.Reflection;
using System.Runtime.InteropServices;

namespace System
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)]
    [ComVisible(true)]
    public sealed class SerializableAttribute : Attribute
    {
        internal static Attribute GetCustomAttribute(RuntimeType type)
        {
            if ((type.Attributes & TypeAttributes.Serializable) != TypeAttributes.Serializable)
            {
                return null;
            }

            return new SerializableAttribute();
        }

        internal static bool IsDefined(RuntimeType type)
        {
            return type.IsSerializable;
        }
    }
}
#if false // 反编译日志
缓存中的 9 项
#endif

2. Passen Sie eine Funktion an

using System;

namespace MyAttribute
{    
    public class CustomAttribute : Attribute
    {
        
    }
}

Die Konvention besteht darin, mit dem Attribut zu enden, das beim Markieren weggelassen werden kann; Sie können es in eckige Klammern setzen und es dann dem Element markieren, das tatsächlich den Konstruktor aufruft;

using System;

namespace MyAttribute
{
    [Custom]
    public class Student
    {
        [Custom]
        public int Id { get; set; }
        public string Name { get; set; }
        [Custom]
        public void Study()
        {
            Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习");
        }
    }
}

3. AttributeVerwendungsmerkmale

Das direkte Hinzufügen mehrerer identischer Attribute zu einem Element führt zu doppelten Attributfehlern. Sie müssen dem Attribut Attribut-Tags [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] hinzufügen, damit Sie demselben Element mehrere identische Attribute hinzufügen können.

using System;

namespace MyAttribute
{
    [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
    public class CustomAttribute : Attribute
    {
        public CustomAttribute()
        {
            Console.WriteLine($"{this.GetType().Name} 无参数构造函数执行");
        }
        public CustomAttribute(int id)
        {
            Console.WriteLine($"{this.GetType().Name} int参数构造函数执行");
            this._Id = id;
        }
        public CustomAttribute(string name)
        {
            Console.WriteLine($"{this.GetType().Name} string参数构造函数执行");
            this._Name = name;
        }
    }
}

Anzeige mehrerer identischer Merkmale

using System;

namespace MyAttribute
{    
    [Custom]
    [Custom()]    
    [Custom(0)]    
    public class Student
    {
        [Custom]
        public int Id { get; set; }
        public string Name { get; set; }
        [Custom]
        public void Study()
        {
            Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习");
        }
       
        [Custom(0)]
        public string Answer([Custom]string name)
        {
            return $"This is {name}";
        }
    }
}

Das AttributeUsage-Attribut wirkt sich auf den Betrieb des Compilers aus. Es gibt das geänderte Objekt an, ob es wiederholt geändert werden kann und ob die geänderte Attributunterklasse wirksam wird. Es wird empfohlen, die verwendeten Objekte klar einzuschränken.

[AttributeUsage(AttributeTargets.Method|AttributeTargets.Class|AttributeTargets.Property, AllowMultiple = true)]

4. Features können Attribute und Felder angeben

using System;

namespace MyAttribute
{

    [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
    public class CustomAttribute : Attribute
    {
        public CustomAttribute()
        {
            Console.WriteLine($"{this.GetType().Name} 无参数构造函数执行");
        }
        public CustomAttribute(int id)
        {
            Console.WriteLine($"{this.GetType().Name} int参数构造函数执行");
            this._Id = id;
        }
        public CustomAttribute(string name)
        {
            Console.WriteLine($"{this.GetType().Name} string参数构造函数执行");
            this._Name = name;
        }

        private int _Id = 0;
        private string _Name = null;

        public string Remark;
        public string Description { get; set; }
    }
}
using System;

namespace MyAttribute
{
    [Custom(Remark = "123")]
    [Custom(Remark = "123", Description = "456")]
    [Custom(0, Remark = "123")]
    [Custom(0, Remark = "123", Description = "456")]
    public class Student
    {        
        public int Id { get; set; }
        public string Name { get; set; }
        
        public void Study()
        {
            Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习");
        }        
    }
}

5. Funktionen können auch Rückgabewerte und Parameter ändern

using System;

namespace MyAttribute
{
    public class Student
    {
        [return: Custom]
        public string Answer([Custom]string name)
        {
            return $"This is {name}";
        }
    }
}

6. Mehrere Änderungen können durch eckige Klammern oder Kommas innerhalb einer eckigen Klammer getrennt werden.

using System;

namespace MyAttribute
{
    [Custom]
    [Custom()]
    [Custom(Remark = "123")]
    [Custom(Remark = "123", Description = "456")]
    [Custom(0)]
    [Custom(0, Remark = "123")]
    [Custom(0, Remark = "123", Description = "456")]
    public class Student
    {
        [return: Custom, Custom,Custom(), Custom(0, Remark = "123", Description = "456")]        
        public string Answer(string name)
        {
            return $"This is {name}";
        }
    }
}

3. Funktionsprinzip der Funktion

Benutzerdefinierte Funktionen scheinen bedeutungslos zu sein. Wie generieren die vom Framework bereitgestellten Funktionen also einen Wert? [Obsolete][AttributeUsage] wirkt sich auf den Compiler aus. Dies ist im System integriert und wir können es nicht tun.

Nach der Dekompilierung wurde festgestellt, dass die Funktion .custom innerhalb des Elements generiert, auf das wir in C# nicht zugreifen können. Es ist verständlich, dass sich die Funktion in keiner Weise geändert hat. Doch wie genau generiert das Framework Funktionalität?

Feature-Instanzen können durch Reflektion aus Typen, Eigenschaften und Methoden abgerufen werden. Es ist erforderlich, zuerst IsDefined zu erkennen und dann eine Instanziierung zu erhalten. Features können gefunden werden, wenn das Programm ausgeführt wird und ein InvokeCenter eines Drittanbieters benötigt wird. Hier können die Features aktiv erkannt und verwendet werden, um ihm Funktionen zu verleihen. Es ist sinnlos, nur Features zu definieren.

using System;

namespace MyAttribute
{
    public class InvokeCenter
    {
        public static void ManagerStudent<T>(T student) where T : Student
        {
            Console.WriteLine($"{student.Id}_{student.Name}");
            student.Study();
            student.Answer("123");

            Type type = student.GetType();
            if (type.IsDefined(typeof(CustomAttribute), true))
            {
                //type.GetCustomAttribute()
                object[] oAttributeArray = type.GetCustomAttributes(typeof(CustomAttribute), true);
                foreach (CustomAttribute attribute in oAttributeArray)
                {
                    attribute.Show();
                    //attribute.Description
                }

                foreach (var prop in type.GetProperties())
                {
                    if (prop.IsDefined(typeof(CustomAttribute), true))
                    {
                        object[] oAttributeArrayProp = prop.GetCustomAttributes(typeof(CustomAttribute), true);
                        foreach (CustomAttribute attribute in oAttributeArrayProp)
                        {
                            attribute.Show();
                        }
                    }
                }
                foreach (var method in type.GetMethods())
                {
                    if (method.IsDefined(typeof(CustomAttribute), true))
                    {
                        object[] oAttributeArrayMethod = method.GetCustomAttributes(typeof(CustomAttribute), true);
                        foreach (CustomAttribute attribute in oAttributeArrayMethod)
                        {
                            attribute.Show();
                        }
                    }
                }
            }
        }
    }
}

Merkmale werden zur Kompilierzeit bestimmt. Konstruktoren/Eigenschaften/Felder können keine Variablen verwenden. Daher kann mvc5-filter nicht injiziert werden, daher wird die Methode zum Injizieren von Filtern im Kern bereitgestellt.

4. Charakteristische Anwendungsfälle

1. Die Aufzählung der Feature-Implementierung zeigt Beschreibungsinformationen an

(1) Erstellen Sie eine Aufzählungsklasse
namespace MyAttribute.EnumExtend
{
    /// <summary>
    /// 用户状态
    /// </summary>
    public enum UserState
    {
        /// <summary>
        /// 正常状态
        /// </summary>
        [Remark("正常状态")]
        Normal = 0,
        /// <summary>
        /// 已冻结
        /// </summary>
        [Remark("已冻结")]
        Frozen = 1,
        /// <summary>
        /// 已删除
        /// </summary>
        [Remark("已删除")]
        Deleted = 2
    }
}
(2) Erstellen Sie Feature-Classes
using System;

namespace MyAttribute.EnumExtend
{
    /// <summary>
    /// Remark特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    public class RemarkAttribute : Attribute
    {
        public string Remark { get; private set; }
        public RemarkAttribute(string remark)
        {
            this.Remark = remark;
        }
    }
}
(3) Aufzählungserweiterungsmethode
using System;
using System.Reflection;

namespace MyAttribute.EnumExtend
{
    public static class AttributeExtend
    {
        public static string GetRemark(this Enum value)
        {
            Type type = value.GetType();
            var field = type.GetField(value.ToString());
            if (field.IsDefined(typeof(RemarkAttribute), true))
            {
                RemarkAttribute attribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute), true);
                return attribute.Remark;
            }
            else
            {
                return value.ToString();
            }
        }
    }
}
(4) Aufzählung ruft Erweiterungsmethoden auf
using MyAttribute.EnumExtend;
using MyAttribute.ValidateExtend;
using System;

namespace MyAttribute
{
    /// <summary>
    /// main方法调用
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                #region 特性实现枚举展示描述信息
                {
                    UserState userState = UserState.Frozen;                    
                    string reamrk = userState.GetRemark();
                    //有了特性,文字其实是直接固化在枚举上面, 如果修改只用改这里
                    //1 数据展示--不想展示属性名字,而是用一个中文描述
                    //2 想指定哪个是主键 哪个是自增
                    //3 别名--数据库里面叫A 程序叫B,怎么映射起来
                }
                #endregion
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.Read();
        }
    }
}

2. Überprüfung der Funktionsimplementierungsdaten

(1) Abstrakte Merkmale der Basisklasse
using System;

namespace MyAttribute.ValidateExtend
{
    public abstract class AbstractValidateAttribute : Attribute
    {
        public abstract bool Validate(object oValue);
    }
}
(2) Implementierung von Unterklassenmerkmalen – digitale Länge
using System;

namespace MyAttribute.ValidateExtend
{
    [AttributeUsage(AttributeTargets.Property)]
    public class LongAttribute : AbstractValidateAttribute
    {
        private long _Min = 0;
        private long _Max = 0;
        public LongAttribute(long min, long max)
        {
            this._Min = min;
            this._Max = max;
        }

        public override bool Validate(object oValue)
        {
            return oValue != null
                && long.TryParse(oValue.ToString(), out long lValue)
                && lValue >= this._Min
                && lValue <= this._Max;
        }
    }
}
(3) Implementierung von Unterklassenfunktionen – nullbar
namespace MyAttribute.ValidateExtend
{
    public class RequiredAttribute : AbstractValidateAttribute
    {
        public override bool Validate(object oValue)
        {
            return oValue != null
                && !string.IsNullOrWhiteSpace(oValue.ToString());
        }
    }
}
(4) Implementierung von Unterklassenfunktionen – Stringlänge
using System;

namespace MyAttribute.ValidateExtend
{
    [AttributeUsage(AttributeTargets.Property)]
    public class StringLengthAttribute : AbstractValidateAttribute
    {
        private int _Min = 0;
        private int _Max = 0;
        public StringLengthAttribute(int min, int max)
        {
            this._Min = min;
            this._Max = max;
        }

        public override bool Validate(object oValue)
        {
            return oValue != null
                && oValue.ToString().Length >= this._Min
                && oValue.ToString().Length <= this._Max;
        }
    }
}
(5) Generische Erweiterungsmethode
using System;

namespace MyAttribute.ValidateExtend
{
    public static class AttributeExtend
    {
        public static bool Validate<T>(this T t)
        {
            Type type = t.GetType();
            foreach (var prop in type.GetProperties())
            {
                if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
                {
                    object oValue = prop.GetValue(t);
                    foreach (AbstractValidateAttribute attribute in prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true))
                    {
                        if (!attribute.Validate(oValue))
                            return false;
                    }
                }
            }
            return true;
        }
    }
}
(6) Allgemeine Klassenfelddefinition
using System;

namespace MyAttribute.ValidateExtend
{
    public static class AttributeExtend
    {
        public static bool Validate<T>(this T t)
        {
            Type type = t.GetType();
            foreach (var prop in type.GetProperties())
            {
                if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
                {
                    object oValue = prop.GetValue(t);
                    foreach (AbstractValidateAttribute attribute in prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true))
                    {
                        if (!attribute.Validate(oValue))
                            return false;
                    }
                }
            }
            return tue;
        }
    }
}
(7) Die Klasse ruft die Erweiterungsmethode auf, um das Feld zu überprüfen
using MyAttribute.EnumExtend;
using MyAttribute.ValidateExtend;
using System;

namespace MyAttribute
{
    /// <summary>
    /// main方法调用
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {                
                #region 特性实现数据验证,并且可扩展
                {
                    //通过特性去提供额外行为
                    //数据验证--到处都需要验证
                    StudentVip student = new StudentVip()
                    {
                        Id = 123,
                        Name = "无为",
                        QQ = 729220650,
                        Salary = 1010000
                    };                    

                    if (student.Validate())
                    {
                        Console.WriteLine("特性校验成功");
                    }
                    //1 可以校验多个属性
                    //2 支持多重校验
                    //3 支持规则的随意扩展
                }
                #endregion
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.Read();
        }
    }
}

Guess you like

Origin blog.csdn.net/liyou123456789/article/details/119314247#comments_30263798