C#语言学习之旅(10)特性与反射

反射是用来描述在运行过程中检查和处理程序元素的功能。也就是能够动态处理程序元素。

 10.1 定制特性

定制特性是把定制的元数据 和程序元素关联起来,这些元素是在编译过程中创建的,并且嵌入到程序集中。

 a.定义一个特性

定义特性
 [AttributeUsage(
        AttributeTargets.Class 
| AttributeTargets.Method,
        AllowMultiple 
= true, Inherited = false)]
    
public class LastModifiedAttribute : Attribute
    {
        
private readonly DateTime dateModified;
        
private readonly string changes;
        
private string issues;

        
public LastModifiedAttribute(string dateModified, string changes)
        {
            
this.dateModified = DateTime.Parse(dateModified);
            
this.changes = changes;
        }

        
public DateTime DateModified
        {
            
get { return dateModified; }
        }

        
public string Changes
        {
            
get { return changes; }
        }
        
        
public string Issues
        {
            
get { return issues; }
            
set { issues = value; }
       

 说明:可以使用AttributeTargets.all指定特性可以应用到所有类型的程序元素上.另外参数说明:AllowMultiple参数表示这个特性是否可以多次应用到同一项上, Inherited表示应用到类或接口上的特性是否可以自动应用到其派生类或接口上。true表示可以应用到派生类接口中去。

b.使用定制特性

使用定制特性
using System;
using Wrox.ProCSharp.WhatsNewAttributes;
using System.Collections;
using System.Text;

[assembly: SupportsWhatsNew]

namespace Wrox.ProCSharp.VectorClass
{
    [LastModified(
"14 Feb 2008""IEnumerable interface implemented " +
        
"So Vector can now be treated as a collection")]
    [LastModified(
"10 Feb 2008""IFormattable interface implemented " +
        
"So Vector now responds to format specifiers N and VE")]
    
class Vector : IFormattable, IEnumerable
    {
        
public double x, y, z;

        
public Vector(double x, double y, double z)
        {
            
this.x = x;
            
this.y = y;
            
this.z = z;
        }

        [LastModified(
"10 Feb 2008""Method added in order to provide formatting support")]
        
public string ToString(string format, IFormatProvider formatProvider)
        {
            
if (format == null)
                
return ToString();
            
string formatUpper = format.ToUpper();
            
switch (formatUpper)
            {
                
case "N":
                    
return "|| " + Norm().ToString() + " ||";
                
case "VE":
                    
return String.Format("( {0:E}, {1:E}, {2:E} )", x, y, z);
                
case "IJK":
                    StringBuilder sb 
= new StringBuilder(x.ToString(), 30);
                    sb.Append(
" i + ");
                    sb.Append(y.ToString());
                    sb.Append(
" j + ");
                    sb.Append(z.ToString());
                    sb.Append(
" k");
                    
return sb.ToString();
                
default:
                    
return ToString();
            }
        }

        
public Vector(Vector rhs)
        {
            x 
= rhs.x;
            y 
= rhs.y;
            z 
= rhs.z;
        }

        [LastModified(
"14 Feb 2008""Method added in order to provide collection support")]
        
public IEnumerator GetEnumerator()
        {
            
return new VectorEnumerator(this);
        }

        
public override string ToString()
        {
            
return "" + x + " , " + y + " , " + z + " )";
        }

        
public double this[uint i]
        {
            
get
            {
                
switch (i)
                {
                    
case 0:
                        
return x;
                    
case 1:
                        
return y;
                    
case 2:
                        
return z;
                    
default:
                        
throw new IndexOutOfRangeException(
                           
"Attempt to retrieve Vector element" + i);
                }
            }
            
set
            {
                
switch (i)
                {
                    
case 0:
                        x 
= value;
                        
break;
                    
case 1:
                        y 
= value;
                        
break;
                    
case 2:
                        z 
= value;
                        
break;
                    
default:
                        
throw new IndexOutOfRangeException(
                           
"Attempt to set Vector element" + i);
                }
            }
        }

        
public static bool operator ==(Vector lhs, Vector rhs)
        {
            
if (System.Math.Abs(lhs.x - rhs.x) < double.Epsilon &&
               System.Math.Abs(lhs.y 
- rhs.y) < double.Epsilon &&
               System.Math.Abs(lhs.z 
- rhs.z) < double.Epsilon)
                
return true;
            
else
                
return false;
        }

        
public static bool operator !=(Vector lhs, Vector rhs)
        {
            
return !(lhs == rhs);
        }

        
public static Vector operator +(Vector lhs, Vector rhs)
        {
            Vector Result 
= new Vector(lhs);
            Result.x 
+= rhs.x;
            Result.y 
+= rhs.y;
            Result.z 
+= rhs.z;
            
return Result;
        }

        
public static Vector operator *(double lhs, Vector rhs)
        {
            
return new Vector(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
        }

        
public static Vector operator *(Vector lhs, double rhs)
        {
            
return rhs * lhs;
        }

        
public static double operator *(Vector lhs, Vector rhs)
        {
            
return lhs.x * rhs.x + lhs.y + rhs.y + lhs.z * rhs.z;
        }

        
public double Norm()
        {
            
return x * x + y * y + z * z;
        }

        
#region enumerator class
        [LastModified(
"14 Feb 2008""Class created as part of collection support for Vector")]
        
private class VectorEnumerator : IEnumerator
        {
            Vector theVector;      
// Vector object that this enumerato refers to 
            int location;   // which element of theVector the enumerator is currently referring to 

            
public VectorEnumerator(Vector theVector)
            {
                
this.theVector = theVector;
                location 
= -1;
            }

            
public bool MoveNext()
            {
                
++location;
                
return (location > 2? false : true;
            }

            
public object Current
            {
                
get
                {
                    
if (location < 0 || location > 2)
                        
throw new InvalidOperationException(
                           
"The enumerator is either before the first element or " +
                           
"after the last element of the Vector");
                    
return theVector[(uint)location];
                }
            }

            
public void Reset()
            {
                location 
= -1;
            }

        }
        
#endregion
    }
}

 说明: [LastModified("10 Feb 2008", "Method added in order to provide formatting support")]实现特性的构造函数的初始化,即实现了可选参数。

10.2 反射

 a.system.type类

通过这个类可以访问任何给定数据类型的信息。type类是一个抽象的基类。只要实例化了一个type对象就是实例化他的一个派生类。

常见使用方法

1.Type t=typeof(double);

2.double d=10; Type t=d.GetType();

3.Type t=Type.GetType("System.Double");

下面给出个例子:该例子主要是用来处理double类型的

system.type 例子
using System;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace TypeView
{
    
internal class Program
    {
        
private static void Main()
        {
            
// modify this line to retrieve details of any
            
// other data type
            Type t = typeof (double);//类型的名称
           
            AnalyzeType(t);

            MessageBox.Show(OutputText.ToString(), 
"Analysis of type " + t.Name);
            Console.ReadLine();
        }

        
private static void AnalyzeType(Type t)
        {
            AddToOutput(
"Type Name:  " + t.Name);
            AddToOutput(
"Full Name:  " + t.FullName);
            AddToOutput(
"Namespace:  " + t.Namespace);
            Type tBase 
= t.BaseType;
            
if (tBase != null)
                AddToOutput(
"Base Type:" + tBase.Name);
            Type tUnderlyingSystem 
= t.UnderlyingSystemType;
            
if (tUnderlyingSystem != null)
                AddToOutput(
"UnderlyingSystem Type:" + tUnderlyingSystem.Name);

            AddToOutput(
"\nPUBLIC MEMBERS:");
            MemberInfo[] Members 
= t.GetMembers();//获得成员信息
            foreach (MemberInfo NextMember in Members)
            {
                AddToOutput(NextMember.DeclaringType 
+ " " + NextMember.MemberType +
                            
" " + NextMember.Name);
            }
        }

        
private static void AddToOutput(string Text)
        {
            OutputText.Append(
"\n" + Text);
        }

        
private static readonly StringBuilder OutputText = new StringBuilder(500);
    }
}

 b.Assembly类

该类主要是允许访问给定程序集得元数据,也可以加载和执行程序集的方法,在使用Assembly实例之前需要把相应的程序集加载到运行进程中。可以使用静态成员Assembly.Load()或者Assembly.LoadForm()。两个方法之间区别Load

参数是程序集名称,运行库会在各个位置搜索该程序集。LoadForm()的参数是程序集的完成路径名称,不会再到其他地方进行搜索啦。

  Assembly a = Assembly.Load("someAssembly");
  Assembly a1 = Assembly.LoadFrom(@"c:\someAssembly");

 下面是使用反射的例子:

反射
using System;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Wrox.ProCSharp.WhatsNewAttributes;

namespace Wrox.ProCSharp.LookUpWhatsNew
{
    
internal class WhatsNewChecker
    {
        
private static DateTime backDateTo = new DateTime(200821);
        
private static readonly StringBuilder outputText = new StringBuilder(1000);

        
private static void Main()
        {
            Assembly theAssembly 
= Assembly.Load("VectorClass");//加载程序集,这个名称是程序集名称,而不是命名空间
          
            Attribute supportsAttribute 
=
                Attribute.GetCustomAttribute(
                    theAssembly, 
typeof (SupportsWhatsNewAttribute));//获得用户自定义的属性
            string Name = theAssembly.FullName;

            AddToMessage(
"Assembly: " + Name);
            
if (supportsAttribute == null)
            {
                AddToMessage(
                    
"This assembly does not support WhatsNew attributes");
                
return;
            }
            
else
                AddToMessage(
"Defined Types:");

            Type[] types 
= theAssembly.GetTypes();
            
foreach (Type definedType in types)
                DisplayTypeInfo(theAssembly, definedType);

            MessageBox.Show(outputText.ToString(),
                            
"What\'s New since " + backDateTo.ToLongDateString());
            Console.ReadLine();
        }

        
private static void DisplayTypeInfo(Assembly theAssembly, Type type)
        {
            
// make sure we only pick out classes
            if (!(type.IsClass))
                
return;
            AddToMessage(
"\nclass " + type.Name);

            Attribute[] attribs 
= Attribute.GetCustomAttributes(type);
            
if (attribs.Length == 0)
                AddToMessage(
"No changes to this class");
            
else
                
foreach (Attribute attrib in attribs)
                    WriteAttributeInfo(attrib);

            MethodInfo[] methods 
= type.GetMethods();
            AddToMessage(
"CHANGES TO METHODS OF THIS CLASS:");
            
foreach (MethodInfo nextMethod in methods)
            {
                
object[] attribs2 =
                    nextMethod.GetCustomAttributes(
                        
typeof (LastModifiedAttribute), false);
                
if (attribs != null)
                {
                    AddToMessage(
                        nextMethod.ReturnType 
+ " " + nextMethod.Name + "()");
                    
foreach (Attribute nextAttrib in attribs2)
                        WriteAttributeInfo(nextAttrib);
                }
            }
        }

        
private static void WriteAttributeInfo(Attribute attrib)
        {
            LastModifiedAttribute lastModifiedAttrib 
=
                attrib 
as LastModifiedAttribute;
            
if (lastModifiedAttrib == null)
                
return;

            
// check that date is in range
            DateTime modifiedDate = lastModifiedAttrib.DateModified;
            
            
if (modifiedDate < backDateTo)
                
return;

            AddToMessage(
"  MODIFIED: " +
                         modifiedDate.ToLongDateString() 
+ ":");
            AddToMessage(
"    " + lastModifiedAttrib.Changes);
            
if (lastModifiedAttrib.Issues != null)
                AddToMessage(
"    Outstanding issues:" +
                             lastModifiedAttrib.Issues);
        }

        
private static void AddToMessage(string message)
        {
            outputText.Append(
"\n" + message);
        }
    }
}

小结:这章节写的主要都是定制特性,以及最后讲了如何使用反射来使用特性。对反射的讲解不是很多。如果相对反射进一步了解可以参考 AXzhzC#反射Reflection学习随笔(完结篇)_AX

原文地址:https://www.cnblogs.com/ylwn817/p/2078185.html