反射落成Model修改前后的始末相比较,自定义个性实例

在支付进度中,大家会遭遇那样1个难点,编辑了四个目标之后,大家想要把那些目的修改了什么样内容保留下来,以便以后查看和追责。

正文只是收十Runtime中,成员变量、属性、关联对象、方法调换使用实例。不会非常细心的任课Runtime的内容,假使想打听Runtime愈来愈多内容,能够移动这里,查看大神们关于Runtime博文。

Reflection,普通话翻译为反射。那是.Net中赚取运转时类型消息的形式

 

 

Reflection,汉译为反射。那是.net中收获运转时类型新闻的主意,.net的应用程序由多少个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供1种编制程序的点子,让技术员能够在程序运营期得到那多少个组成都部队分的相关消息,举例:Assembly类能够获取正在运作的装配件音信,也得以动态的加载装配件,以及在装配件中查找类型音讯,并创设该品种的实例。Type类能够取得对象的类型音讯,此新闻包罗对象的保有因素:方法、构造器、属性等等,通过Type类能够获得这几个成分的音信,并且调用之。MethodInfo包括方法的音信,通过这几个类能够赢得方法的称呼、参数、重回值等,并且能够调用之。诸如此类,还有FieldInfo、伊芙ntInfo等等,那一个类都富含在System.Reflection命名空间下。

一、Type类于获取类型音信

System.Type
类对于反射起着主导的功力。当反射请求加载的花色时,公共语言运营库将为它成立三个Type。您可以应用 Type
对象的主意、字段、属性和嵌套类来搜索有关该项目标持有音讯。

世家运营一下底下的代码依据结果分析一下就能够比较清楚的驾驭Type了

获得类型消息

namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MyClass m = new MyClass();
Type type = m.GetType();
Console.WriteLine("类型名:" + type.Name);
Console.WriteLine("类全名:"+type.FullName);
Console.WriteLine("命名空间名:"+type.Namespace);
Console.WriteLine("程序集名:"+type.Assembly);
Console.WriteLine("模块名:"+type.Module);
Console.WriteLine("基类名:"+type.BaseType);
Console.WriteLine("是否类:"+type.IsClass);
Console.WriteLine("类的公共成员:");
MemberInfo[] memberInfos = type.GetMembers();//得到所有公共成员
foreach (var item in memberInfos)
{
Console.WriteLine("{0}:{1}",item.MemberType,item);
}
}
}
class MyClass
{
public string m;
public void test()
{ }
public int MyProperty { get; set; }

}
}

二、获取程序集元数据

Assembly类定义了三个程序集,它是二个可选择、无版本抵触并且可本身描述的公共语言运维库应用程序构造块。因为程序聚焦是利用元数据举办自己描述的,所以我们就能因而其元数据拿到程序集内部的组成。结合Assembly和反光能够收获程序集的元数据,不过首先要将先后集装入内部存储器中。可以利用Assembly类的有余静态Load方法加载程序集。

下边的先后突显程序集的音信

public static void Main()
{
//获取当前执行代码的程序集
Assembly assem = Assembly.GetExecutingAssembly();

Console.WriteLine(“程序集全名:”+assem.FullName);
Console.WriteLine(“程序集的版本:”+assem.GetName().Version);
Console.WriteLine(“程序集伊始地点:”+assem.CodeBase);
Console.WriteLine(“程序集地方:”+assem.Location);
Console.WriteLine(“程序集入口:”+assem.EntryPoint);

Type[] types = assem.GetTypes();
Console.WriteLine(“程序集下富含的连串:”);
foreach (var item in types)
{
Console.WriteLine(“类:”+item.Name);
}

}

三、动态加载类型

早绑定是在编译时绑定对象类型,而晚绑定是在运维时才绑定对象的花色。利用反射能够兑现晚绑定,即动态加载类型,并调用他们的点子,下边是MSDN中的二个事例,详细的解说音讯见注释

动态加载类型

namespace ConsoleApplication2
{
public class Example
{
private int factor;
public Example(int f)
{
factor = f;
}

public int SampleMethod(int x)
{
Console.WriteLine(“\nExample.SampleMethod({0}) executes.”, x);
return x * factor;
}

public static void Main()
{
//获取当前进行代码的主次集
Assembly assem = Assembly.GetExecutingAssembly();

Console.WriteLine(“Assembly Full Name:”);
Console.WriteLine(assem.FullName);

// The AssemblyName type can be used to
parse the full name.
AssemblyName assemName = assem.GetName();
Console.WriteLine(“\nName: {0}”, assemName.Name);
反射落成Model修改前后的始末相比较,自定义个性实例。Console.WriteLine(“Version: {0}.{1}”,
assemName.Version.Major, assemName.Version.Minor);
Console.WriteLine(“\nAssembly CodeBase:”);
Console.WriteLine(assem.CodeBase);
//
从程序集众创设二个Example实例并且用object类型的引用o指向它,同时调用1个输入参数的构造函数
Object o = assem.CreateInstance(“ConsoleApplication2.Example”, false,
BindingFlags.ExactBinding,
null, new Object[] { 2 }, null, null);

//构造Example类的3个晚绑定的主意SampleMethod 
MethodInfo m =
assem.GetType(“ConsoleApplication2.Example”).GetMethod(“SampleMethod”);
//调用刚才实例化好的Example对象o中的SampleMethod方法,传入的参数为4二
Object ret = m.Invoke(o, new Object[] { 42 });
Console.WriteLine(“SampleMethod returned {0}.”, ret);

Console.WriteLine(“\nAssembly entry
point:”);
Console.WriteLine(assem.EntryPoint);
}
}

反射性格:

[Table(Name="dbo.[User]")]
            public partial class User
            {

当C#编译器开掘那么些天性有一个表征Table时,首先会把字符串Attribute增添到那几个称谓的末尾,造成3个重组名称TableAttribute,然后在其寻觅路线的全数命名空间中追寻有一样类名的类。但要注意,如若该本性名结尾是Attribute,编译器就不会把该字符串加到组合名称中。全部的特色都以从System.Attribute类型上面派生的。

接着我们来看一下Table本性的定制格式

[AttributeUsageAttribute(AttributeTargets.Class,Inherited=true,AllowMultiple=false)]
            public class TalbeAttribute:Attribute
            {

在概念类型时接纳System.AttributeUsage个性来表明这几个自定义脾性的选用范围,这里运用了Class样式,表示TableAttribute特性只可以用在任何的Class类型前面,若放置在Interface或Struct类型前面,或许放在对象成员的目前则会油不过生编写翻译错误。这里依旧用语句
AllowMultiple=false
语句来申明对于三个体系,该性情只可以用三回,若七个Class类型前边出现多少个TableAttribute,则会冒出编写翻译错误。若设置AllowMultiple=true,则该个性能够屡屡定义,相当于三个Class类型前边能够出现四个一样档案的次序的表征。不过这里大家假使2个目的只好照射到3个数据表上,未有多种映射,因而就指明对同二个品种该特性不可能反复应用。Inherited参数设定为true,就意味着应用到类或接口上的天性也足以自行应用到所派生的类或接口上。

 

咱俩再看一下定制TalbeAttribute个性的全部例子:

[AttributeUsageAttribute(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class TableAttribute : Attribute
{
//保存表名的字段
private string _tableName;

public TableAttribute()
{
}

public TableAttribute(string tableName)
{
this._tableName = tableName;
}

///
/// 映射的表名(表的人名:方式名.表名)
///
public string TableName
{
set
{
this._tableName = value;
}
get
{
return this._tableName;
}
}
}

特点也是一个Class类型,能够有三个构造函数,就好像C#的new语句同样,大家向品种附加特色时得以运用分化的开首化参数来指明使用本性的这多少个构造函数。我们附加特色时还足以动用“属性名=属性值”的主意来直接指明天性的属性值。该特性中定义了二个TableName属性,该属性正是被修饰的靶子所映射的数据库表的称号。

上面大家举一个施用本性来举行O/奥德赛Mapping的例证,也正是将对象转化成Sql语句

用户类:

User类

    [Table("User")]
            public class User
            {
            [Colum("userID", DbType = DbType.Int32)]
            public int UserID { get; set; }
            [Colum("UserName", DbType = DbType.String)]
            public string UserName { get; set; }
            }

表特性

[AttributeUsageAttribute(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class TableAttribute : Attribute
{
//保存表名的字段
private string _tableName;

public TableAttribute()
{
亚洲必赢官网 ,}

public TableAttribute(string tableName)
{
this._tableName = tableName;
}

///
/// 映射的表名(表的全名:方式名.表名)
///
public string TableName
{
set
{
this._tableName = value;
}
get
{
return this._tableName;
}
}
}

列特性: 

[AttributeUsageAttribute(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public class ColumAttribute : Attribute
{
private string _columName;

private DbType _dbType ;

public ColumAttribute()
{
}

public ColumAttribute(string columName)
: this()
{
this._columName = columName;
}

public ColumAttribute(string columName, DbType dbType)
: this(columName)
{
this._dbType = dbType;
}

//列名
public virtual string ColumName
{
set
{
this._columName = value;
}
get
{
return this._columName;
}
}

//描述一些万分的数据库类型
public DbType DbType
{
get { return _dbType; }
set { _dbType = value; }
}

ORMHelp
public class ORMHelp
{
public void Insert(object table)
{
Type type = table.GetType();
//定义2个字典来存放表中字段和值的附和系列
Dictionary columValue = new Dictionary();
StringBuilder SqlStr=new StringBuilder();
SqlStr.Append(“insert into “);
//获得表名子
TableAttribute temp =
(TalbeAttribute)type.GetCustomAttributes(typeof(TalbeAttribute),
false).First();
SqlStr.Append(temp.TableName);
SqlStr.Append(“(“);
PropertyInfo[] Propertys=type.GetProperties();
foreach (var item in Propertys)
{
object[] attributes = item.GetCustomAttributes(false);
foreach (var item1 in attributes)
{
//获得对应属性的值
string value= table.GetType().InvokeMember(item.Name,
System.Reflection.BindingFlags.GetProperty, null, table,
null).ToString();
ColumAttribute colum = item1 as ColumAttribute;
if (colum != null)
{
columValue.Add(colum.ColumName,value);
}
}
}
//拼插入操作字符串
foreach (var item in columValue)
{
SqlStr.Append(item.Key);
SqlStr.Append(“,”);

}
SqlStr.Remove(SqlStr.Length-1, 1);
SqlStr.Append(“) values(‘”);
foreach (var item in columValue)
{
SqlStr.Append(item.Value);
SqlStr.Append(“‘,'”);

}
SqlStr.Remove(SqlStr.Length – 2, 2);
SqlStr.Append(“)”);
Console.WriteLine(SqlStr.ToString());

}
}
SqlStr中的内容为insert into User(userID,UserName)
values(‘壹’,’lfm’)

前者采纳代码:

前者代码

static void Main(string[] args)
            {
            ORMHelp o = new ORMHelp();
            User u = new User() { UserID=1,UserName="lfm"};
            o.Insert(u);
            }

 

 

 

应用

事例那一个东西其实挺难弄得,弄个简易的,纵然能声明难题但却轻便让人认为没实用价值,弄个有实用价值却又壹再牵扯许多其余本事乃至牵扯繁多作业逻辑,看起来很复杂很难懂。在那边本身尽大概追求多少个有实用价值又不复杂的事例。

 

 

一、使用反射通过读取配置文件来动态的创办相关类的靶子

大家先来探望Main函数和内需动态加载的靶子在同2个顺序集的情状powered
by
2517伍.net

结构图:

亚洲必赢官网 1

接口

interface ILog
{
bool Write(string message);
bool Write(Exception ex);
}

TextFileLog
class TextFileLog : ILog
{
public bool Write(string message)
{
string fileDir = ConfigurationManager.AppSettings["LogTarget"].ToString();
using (StreamWriter w = File.AppendText(fileDir))
{
// w.Write(" Log Entry : ");
w.WriteLine("发生时间{0}", DateTime.Now.ToLocalTime().ToString());
w.WriteLine("日志内容为:{0}", message);
w.WriteLine("-------------------------------");
// Update the underlying file.
w.Flush();
w.Close();
}
return true;
}
public bool Write(Exception ex)
{

Write(ex.Message);
return true;
}
}

XmlFileLog
class XmlFileLog : ILog
{
public bool Write(string message)
{
string xmlFilePath =
ConfigurationManager.AppSettings[“LogTarget”].ToString();
if (File.Exists(xmlFilePath))
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlFilePath);
XmlDocumentFragment docFrag = doc.CreateDocumentFragment();
XmlNode nod = doc.SelectSingleNode(“Logs”);
docFrag.InnerXml = “” + DateTime.Now.ToLocalTime().ToString()

  • “” + message + “”;
    nod.AppendChild(docFrag);

doc.Save(xmlFilePath);
return true;
}
else
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;     //设置缩进      
settings.ConformanceLevel = ConformanceLevel.Auto;
settings.IndentChars = ” “;
settings.OmitXmlDeclaration = false;
using (XmlWriter writer = XmlWriter.Create(xmlFilePath, settings))
{
//Start writing the XML document
writer.WriteStartDocument(false);
//Start with the root element
writer.WriteStartElement(“Logs”);
writer.WriteStartElement(“Log”);
writer.WriteStartElement(“Time”);
writer.WriteString(DateTime.Now.ToLocalTime().ToString());
writer.WriteEndElement();
writer.WriteStartElement(“Message”);
writer.WriteString(message);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
//Flush the object and write the XML data to the file
writer.Flush();
return true;
}

}
}
public bool Write(Exception ex)
{
Write(ex.Message);
return true;

}
}

App.config配置

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
<appSettings>
<add key=”LogType” value=”LogClassLibrary.TextFileLog”/>
<!–
本程序集配置
<add key=”LogType” value=”ConsoleApplication2.Log例子.TextFileLog”/>
–>
<!– XmlFileLog  TextFileLog–>
<add key=”LogTarget” value=”c:\log.txt”/>
</appSettings>
</configuration>

主程序

public static void Main()
            {
            #region 同程序集下
            System.Type type=System.Type.GetType(ConfigurationManager.AppSettings["LogType"].ToString());
            ILog log = (ILog)Activator.CreateInstance(type);
            log.Write(new Exception("异常测试"));
            #endregion
            }

假诺在分歧的次序集下,那主函数和布局会略有差别

不一样程序集主函数

 public static void Main()
            {
            

#region 不同程序集
string assemblyPath =

Path.Combine(Environment.CurrentDirectory, "LogClassLibrary.dll");
Assembly a = Assembly.LoadFrom(assemblyPath);
Type type = a.GetType(ConfigurationManager.AppSettings["LogType"].ToString());
LogClassLibrary.ILog log =

(LogClassLibrary.ILog)type.InvokeMember(null,

BindingFlags.CreateInstance,null,null,null);
log.Write(new Exception("异常测试"));
#endregion

}

这某些源码下载

源码下载

二、插件编程手艺

插件是指依据一定的接口标准、能够动态加载和平运动作的程序模块。从地方的事例能够看出,通过反射能够12分方便的动态加载程序集。因而,利用反射的动态加载代码技艺,能够很轻松的贯彻插件。插件编制程序的要点是接纳接口来定义插件的功力特色。插件的宿主程序通过接口来确认、装载和施行插件的效果,落成插件功效的有着类都必须兑现定义插件的接口。

此地只是选贴一部分代码,详细分析请看源码

结构图

亚洲必赢官网 2

接口部分

接口

public interface IHost
{
List Plugins { get; }
int LoadPlugins(string path);
ILog GetLog(string name);

}
public interface ILog
{
bool Write(string message);
bool Write(Exception ex);

}

宿主落成

public class Host : IHost
{
private List plugins = new List();
#region IHost 成员 

public List Plugins
{
get { return plugins; }
}

public int LoadPlugins(string path)
{
string[] assemblyFiles = Directory.GetFiles(path, “*.dll”);
foreach (var file in assemblyFiles)
{
Assembly assembly = Assembly.LoadFrom(file);
foreach (var type in assembly.GetExportedTypes())
{
if (type.IsClass && typeof(ILog).IsAssignableFrom(type))
{
ILog plugin = Activator.CreateInstance(type) as ILog;
plugins.Add(plugin);

}
}
}
return plugins.Count;
}

public ILog GetLog(string name)
{
foreach (var item in plugins)
{
if (item.GetType().ToString()==name)
{
return item;
}

}
return null;
}

#endregion
}

ILog的得以完结和上例基本一样,请参见

主程序代码static void Main(string[]
args)
{
Host.Host host = new Host.Host();
host.LoadPlugins(“.”);
InterfaceLayer.ILog log =
host.GetLog(ConfigurationManager.AppSettings[“LogType”].ToString());
log.Write(new Exception(“十分测试”));
}

插件编制程序源码下载

源码下载

三、分析对象,获得目标中的属性值

大家利用应都用过asp.net中的DropdownList,在绑定其值的时候绝大多数情状下大家做的没什么区别的作业,得到数据源,依照数据源中的有个别列绑定控件,下面大家的话说通用景况的管理形式。大家只要求提供数据群集,以及需求绑定到控件的五个脾气(text,value)名就可以。

public class DDlControl
{
private ListControl underlyingList;

public DDlControl(ListControl
underlyingList)
{
this.underlyingList = underlyingList;
}

public void Add(IDDL ddl)
{
underlyingList.Items.Add(new ListItem(ddl.Name, ddl.Value));
}
public void Add(T t, string nameStr, string valueStr)
{
string name = Convert.ToString(t.GetType().InvokeMember
(nameStr, System.Reflection.BindingFlags.GetProperty, null, t, null));
string value = Convert.ToString(t.GetType().InvokeMember
(valueStr, System.Reflection.BindingFlags.GetProperty, null, t,
null));
Add(new DDLStruct(name,value));

}
public void Clear()
{
underlyingList.Items.Clear();
}

public IDDL SelectedItem
{
get
{
ListItem item = underlyingList.SelectedItem;
return new DDLStruct(item.Text, item.Value);
}
}

public void BindTo(IEnumerable list, string
nameStr, string valueStr)
{
Clear();
foreach (var item in list)
{
Add(item, nameStr, valueStr);
}
}

public string SelectValue
{
get
{
return underlyingList.SelectedValue;
}
set
{
underlyingList.SelectedValue=value;
}
}
}
public struct DDLStruct
{
public DDLStruct(string name, string value)
{
this.name = name;
this.value = value;
}
private string name;
private string value;
public string Name
{
get { return name; }
}

public string Value
{
get { return value; }
}
}

 

元数据,就是C#中封装的片段类,不能够修改.类成员的本性被叫做元数据中的注释.

先是大家要开创二个User类

分子变量和总体性

一、什么是特点

 1     public class User
 2     {
 3         private string name;
 4         public string Name
 5         {
 6             get { return name; }
 7             set { name = value; }
 8         }
 9         private string age;
10         public string Age
11         {
12             get { return age; }
13             set { age = value; }
14         }
15         private string sex;
16         public string Sex
17         {
18             get { return sex; }
19             set { sex = value; }
20         }
21     }
定义

一、Ivar:实例变量类型, 其实是一个指向objc_ivar结构体的指针

typedef struct objc_ivar *Ivar;

     (1)属性与本性的分别

下一场在Main函数中表明并早先化二个User对象

操作方法
// 获取成员变量名字const char * ivar_getName;// 获取成员变量类型编码const char * ivar_getTypeEncoding;//获取成员变量的偏移量ptrdiff_t ivar_getOffset;//注:对于id类型或其他类型对象的实例变量,可以调用object_getIvar和object_setIvar直接访问成员变量,而不使用偏移量。

         属性(Property):属性是面向对象观念里所说的卷入在类里面包车型客车数目字段,Get,Set方法。

1             User userA = new User()
2             {
3                 Name = "李四",
4                 Age = "25",
5                 Sex = "男",
6             };
运用实例

User.h

@interface User : NSObject { NSString *_name;}@property NSString *sex;@property (nonatomic, copy) NSDictionary *dict;@property (nonatomic, assign) NSInteger age;@property (nonatomic, assign) double tall;@property (nonatomic, assign) NSUInteger height;- getIvar;- getProperty;@end

User.m

- getIvar{ unsigned int count = 0; //获取所有的成员变量 Ivar *ivars = class_copyIvarList([User class], &count); for (unsigned i = 0; i < count; i ++) { Ivar ivar = ivars[i]; const char *name = ivar_getName; //成员变量名称 const char *type = ivar_getTypeEncoding; //成员变量类型 NSLog(@"类型 %s 的 %s", type, name); } free; //手动释放}

注: class_copyIvarList()方法,请移步在另1篇文章:Objective-C
Runtime:类和目的

出口结果:

LearnRuntime[836:9888] 类型 @"NSString" 的 _nameLearnRuntime[836:9888] 类型 @"NSString" 的 _sexLearnRuntime[836:9888] 类型 @"NSDictionary" 的 _dictLearnRuntime[836:9888] 类型 q 的 _ageLearnRuntime[836:9888] 类型 d 的 _tallLearnRuntime[836:9888] 类型 Q 的 _height

注:关于出口结果为啥是_name, 请移步《招聘3个可相信的 iOS》—参考答案-
1四题

         特性(Attribute):  官方解释:性格是给钦点的某一声称的一则附加的申明性音讯。
允许类似重大字的讲述注明。它对程序中的成分进行标注,如类型、字段、方法、属性等。从.net角度看,天性是壹类别,那些类承接于System.Attribute类,用于对类、属性、方法、事件等张开描述,主要用在反射中。但从面向对象的等级看,其实Attribute是项目等级的,而不是目的品级。

因为要对照对象编排前后的剧情,所以必要备份一下那几个UserA,我们来个深拷贝

定义

1、objc_property_t:是意味Objective-C申明的性质的品类,其实是指向objc_property结构体的指针。

typedef struct objc_property *objc_property_t;

2、objc_property_attribute_t: 定义了品质的特征,结构体如下:

typedef struct { const char *name; /**< The name of the attribute */ const char *value; /**< The value of the attribute (usually empty) */} objc_property_attribute_t;

        
Attributes和.net文件的成分据保存在一起,能够用来向运转时描述您的代码,或然在程序运维的时候影响程序的一言一行。

1 User userB = DeepCopyByXml<User>(userA);

 1         /// <summary>
 2         /// 深拷贝
 3         /// </summary>
 4         /// <typeparam name="T"></typeparam>
 5         /// <param name="obj"></param>
 6         /// <returns></returns>
 7         public static T DeepCopyByXml<T>(T obj) where T : class
 8         {
 9             object retval;
10             using (MemoryStream ms = new MemoryStream())
11             {
12                 XmlSerializer xml = new XmlSerializer(typeof(T));
13                 xml.Serialize(ms, obj);
14                 ms.Seek(0, SeekOrigin.Begin);
15                 retval = xml.Deserialize(ms);
16                 ms.Close();
17             }
18             return (T)retval;
19         }
操作方法
// 获取属性名const char * property_getName(objc_property_t property);// 获取属性特性描述字符串const char * property_getAttributes(objc_property_t property);// 获取属性中指定的特性char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );// 获取属性的特性列表objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount );

注:property_copyAttributeValue和property_copyAttributeList,
重返值在运用后供给手动释放free();

二、脾性的行使

接下去的做事是修改UserA的性质,然后和UserB相比,利用反射来兑现该功用

运用实例

User.m 添加

- getProperty { unsigned int count = 0; // 获取属性列表 objc_property_t * properties = class_copyPropertyList([User class], &count); for (unsigned i = 0; i < count; i ++) { objc_property_t property = properties[i]; const char *name = property_getName; const char *propertyAttr = property_getAttributes; NSLog(@"属性描述为%s的%s", propertyAttr, name); unsigned int attrCount = 0; //属性的特性列表 objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount); for (unsigned i = 0; i < attrCount; i ++) { objc_property_attribute_t attr = attrs[i]; const char *name = attr.name; const char *value = attr.value; NSLog(@"属性的特性描述:%s值:%s", name, value); } free; NSLog; } free(properties);}

出口结果

LearnRuntime[1190:51044] 属性描述为T@"NSString",&,V_sex的sexLearnRuntime[1190:51044] 属性的特性描述:T值:@"NSString"LearnRuntime[1190:51044] 属性的特性描述:&值:LearnRuntime[1190:51044] 属性的特性描述:V值:_sexLearnRuntime[1190:51044] LearnRuntime[1190:51044] 属性描述为T@"NSDictionary",C,N,V_dict的dictLearnRuntime[1190:51044] 属性的特性描述:T值:@"NSDictionary"LearnRuntime[1190:51044] 属性的特性描述:C值:LearnRuntime[1190:51044] 属性的特性描述:N值:LearnRuntime[1190:51044] 属性的特性描述:V值:_dictLearnRuntime[1190:51044] LearnRuntime[1190:51044] 属性描述为Tq,N,V_age的ageLearnRuntime[1190:51044] 属性的特性描述:T值:qLearnRuntime[1190:51044] 属性的特性描述:N值:LearnRuntime[1190:51044] 属性的特性描述:V值:_ageLearnRuntime[1190:51044] LearnRuntime[1190:51044] 属性描述为Td,N,V_tall的tallLearnRuntime[1190:51044] 属性的特性描述:T值:dLearnRuntime[1190:51044] 属性的特性描述:N值:LearnRuntime[1190:51044] 属性的特性描述:V值:_tallLearnRuntime[1190:51044] LearnRuntime[1190:51044] 属性描述为TQ,N,V_height的heightLearnRuntime[1190:51044] 属性的特性描述:T值:QLearnRuntime[1190:51044] 属性的特性描述:N值:LearnRuntime[1190:51044] 属性的特性描述:V值:_height

注:objc_property_getAttribute_t结构体包含name和value,属性如下:

属性类型 name值:T value:变化编码类型 name值:C & W 空 等 value:无非/原子性 name值:空 N(Nonatomic) value:无变量名称 name值:V value:变化

    (1).net中性情用来管理二种难点,举个例子系列化、程序的海东特点、防止即时编写翻译器对程序代码实行优化从而代码轻松调节和测试等等。

        /// <summary>
        /// Model对比
        /// </summary>
        /// <typeparam Name="T"></typeparam>
        /// <param Name="oldModel"></param>
        /// <param Name="newModel"></param>
        private static void CompareModel<T>(T oldModel, T newModel) where T : class
        {
            string changeStr = string.Empty;
            PropertyInfo[] properties = oldModel.GetType().GetProperties();
            Console.WriteLine("--------用户信息修改汇总--------");
            foreach (System.Reflection.PropertyInfo item in properties)
            {string name = item.Name;
                object oldValue = item.GetValue(oldModel);
                object newValue = item.GetValue(newModel);
                if (!oldValue.Equals(newValue))
                {
                    Console.WriteLine(name + " :由[" + oldValue + "] 改为 [" + newValue + "]");
                }
            }
        }

论及对象(Associated objects)

Associated objects是Objective-C
贰.0运作时三个特点。<objc/runtime.h>中定义几个允许将别的键值在运作时涉嫌到对象上的函数:

objc_setAssociatedObjectobjc_getAssociatedObjectobjc_removeAssociatedObjects

选择八个函数,开拓者能够对曾经存在的类扩大中增添自定义的性质

一旦你品味采用objc_removeAssociatedObjects()举行删减操作,但官方文档告诉大家不应有手动调用这几个函数,日常使用objc_setAssocatedObject方法传入nil值清除关联。关于AssociatedObjects相关知识,请看NShipster上的篇章Associated
Objects。

NSObject+AssociatedObject.h

@interface NSObject (AssociatedObject)@property (nonatomic, strong) id associatedObject;@end

NSObject+AssociatedObject.m

@implementation NSObject (AssociatedObject)@dynamic associatedObject;- setAssociatedObject:object { objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- associatedObject { return objc_getAssociatedObject(self, @selector(associatedObject));}

   
 定植特性的原形上是多少个类的成分上去增多附加音信,并在运维其通过反射得到该附加消息(在选拔数据实体对象时日常使用)

亚洲必赢官网 3

艺术调换(Method swizzling)

Method
Swizzling是退换selector的实际贯彻的本事,通过它能够在运行时经过修改类的分发布中selector对应的函数,来修章的兑现。

//获取实例方法class_getInstanceMethod//获取方法的实现method_getImplementation//获取实现的编码类型method_getTypeEncoding//给方法添加实现class_addMethod//用一个方法的实现替换另一个方法的实class_replaceMethod//交换两个方法的实现method_exchangeImplementations

将UIViewController中的View威尔Appear:方法替换来自定义方法

#import <objc/runtime.h>@implementation UIViewController /** * 理解: [self class] 和 object_getClass区别和联系? */ + load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class class = [self class]; //注意:如果是类方法,则需要 Class class = object_getClass; SEL originalSelector = @selector(viewWillAppear:); SEL swizzledSelector = @selector(xxx_viewWillAppear:); Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); //注意: 在交换方法实现,需要判断原有方法实现是否存在,存在才能交换 // 如何判断?添加原有方法,如果成功,表示原有方法不存在,失败,表示原有方法存在 // 原有方法可能没有实现,所以这里添加方法实现,用自己方法实现 // 这样做的好处:方法不存在,直接把自己方法的实现作为原有方法的实现,调用原有方法,就会来到当前方法的实现 BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (didAddMethod) { class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } });}/** * 添加自定义的方法 * * @param animated */- xxx_viewWillAppear:  animated { [self xxx_viewWillAppear:animated]; //这里不会造成死循环,为什么呢? NSLog(@"viewWillAppear: %@", self);}@end

利用method swizzling
修改UIViewController的@selector(view威尔Appear:)对应的函数指针,指向自定义的xxx_view威尔Appear:的贯彻。具体疏解请看Method
Swizzling。

    (2)Attribute 作为编写翻译器的命令时的应用

 从运转结果来看我们曾经赢获得了修改的剧情,美中不足的是“Name”和“Age”,怎样以粤语显示属性名,接下去将利用C#的风味来得以落成

小结

小说作为读书笔记,目标是便利未来翻看。其余,自己才能轻易,如有错误迎接指正。

        
Conditional:起条件编写翻译的效应,只有知足条件,才同意编写翻译器对它的代码实行编写翻译。一般在程序调节和测试的时候使用

新建二个自定义的特色类TableAttribute

参考资料

此处整理有关Runtime杰出博文。

         DllImport:
用来标志费.net的函数,注解该措施在2个外表的DLL中定义。

    /*     
    参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
    参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
    参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。
     */
    [AttributeUsage(AttributeTargets.Class |
    AttributeTargets.Field |
    AttributeTargets.Property,
          AllowMultiple = false,
          Inherited = false)]
    public class TableAttribute : System.Attribute
    {
        private string fieldName;
        private string tableName;
        /// <summary>
        /// 表名
        /// </summary>
        public string TableName
        {
            get { return tableName; }
            set { tableName = value; }
        }
        /// <summary>
        /// 字段名
        /// </summary>
        public string FieldName
        {
            get { return fieldName; }
            set { fieldName = value; }
        }
    }

         Obsolete: 这一个脾气用来标记当前的办法已经抛弃,不再行使

继之修改User类,加上自定义的风味TableAttribute

      
注:Attribute是多个类,由此DllImport也是二个类,Attribute类是在编写翻译的时候实例化,而不是像一般那样在运行时实例化。

    /// <summary>
    /// 用户信息实体类
    /// </summary>
    [TableAttribute(TableName = "用户信息")]
    public class User
    {
        private string name;
        [TableAttribute(FieldName = "姓名")]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private string age;
        [TableAttribute(FieldName = "年龄")]
        public string Age
        {
            get { return age; }
            set { age = value; }
        }
        private string sex;
        [TableAttribute(FieldName = "性别")]
        public string Sex
        {
            get { return sex; }
            set { sex = value; }
        }
    }

         CLSCompliant: 保险百分百程序集代码遵循CLS,不然编译将报错。

最终修改一下CompareModel这么些主意

 3、自定义本性

 1         /// <summary>
 2         /// Model对比
 3         /// </summary>
 4         /// <typeparam Name="T"></typeparam>
 5         /// <param Name="oldModel"></param>
 6         /// <param Name="newModel"></param>
 7         private static void CompareModel<T>(T oldModel, T newModel) where T : class
 8         {
 9             string changeStr = string.Empty;
10             PropertyInfo[] properties = oldModel.GetType().GetProperties();
11             Console.WriteLine("--------用户信息修改汇总--------");
12             foreach (System.Reflection.PropertyInfo item in properties)
13             {
14                 TableAttribute tableAttribute = item.GetCustomAttribute<TableAttribute>();
15                 string name = item.Name;
16                 if (tableAttribute != null)
17                     name = tableAttribute.FieldName;
18                 object oldValue = item.GetValue(oldModel);
19                 object newValue = item.GetValue(newModel);
20                 if (!oldValue.Equals(newValue))
21                 {
22                     Console.WriteLine(name + " :由[" + oldValue + "] 改为 [" + newValue + "]");
23                 }
24             }
25         }

      使用AttributeUsage,来支配什么接纳新定义的性情

我们看一下一周转结果

     [AttributeUsageAttribute(AttributeTargets.All 
能够行使到其余因素

亚洲必赢官网 4

      ,AllowMultiple=true,
允许使用数10次,大家的定值性格能或无法被重复放在同五个先后实体前反复。

 完整demo下载:

      ,Inherited=false,不三番五次到派生

(完)

        )]

     
天性也是八个类,必须继续于System.Attribute类,取名标准为“类名”+Attribute。不管是一贯或许直接接轨,都会成为二个性子类,性情类的扬言定义了1种可以停放在注解之上新的特色。

     public class MyselfAttribute:System.Attribute

肆、自定义本性案例
     以下用二个接近于Hibernate中Session的Save()方法效果,自动持久化对象消息到数据库来验证自定义性情的选拔。

(1)建立Dept表

Create Table Dept(  
    deptNo int identity(1,1) primary key,  
    dname nvarchar(10) not null,  
    description nvarchar(100)  
)  
Go  
-- 何问起 hovertree.com 

(2)自定义特性

/**************自定义特性类*****************/  
/// <summary>  
/// 作用:用来说明表名是什么  
/// AttributeUsage:说明特性的目标元素是什么  
/// AttributeTargets.Class:代表目标元素为Class  
/// </summary>  
[AttributeUsage(AttributeTargets.Class)]  
public class TableAttribute : Attribute{  

    /// <summary>  
    /// 表名  
    /// </summary>  
    public string TableName { get; set; }  

    #region 构造方法,可选的  

    public TableAttribute() {    }  
    public TableAttribute(string tableName) {  
        this.TableName = tableName;  
    }   

    #endregion  
}  

/**************自定义特性类*****************/  
/// <summary>  
/// 作用:说明列是否为自动增长列  
/// </summary>  
[AttributeUsage(AttributeTargets.Property)]  
class IdentityAttribute: Attribute  
{  
    /// <summary>  
    /// true:是; false:否  
    /// </summary>  
    public bool IsIdentity { get; set; }  
}  

/****************实体类***************/  
/// <summary>  
/// 有意将类名定义成与表名不一致  
/// 用Table特性来说明实体类对应的表名是什么  
/// </summary>  
[Table(TableName = "Dept")]  
public class Department {  

    /// <summary>  
    /// 部门编号,用特性标注为自动增长  
    /// </summary>  
    [Identity(IsIdentity=true)]  
    public int DeptNo { get; set; }  

    /// <summary>  
    /// 部门名称  
    /// </summary>  
    public string Dname { get; set; }  

    /// <summary>  
    /// 部门描述  
    /// </summary>  
    public string Description { get; set; }  

    public Department( string name, string desc) {  
        Dname = name;  
        Description = desc;  
    }  
}  

/****************执行持久化操作类***************/  
/// <summary>  
/// 执行持久化操作类  
/// </summary>  
public class ADOManager {  

    /// <summary>  
    /// 将对象的属性值作为表中对应列的值来添加  
    /// </summary>  
    /// <param name="obj">要添加的对象</param>  
    public int Save(Object obj) {  
        //1.取得类名:代表表名,用到反射  
        string tableName = obj.GetType().Name;  
        //如果类有TableAttribute特性,在采用特性说明的类名  
        TableAttribute attr = Attribute.GetCustomAttribute(obj.GetType(), typeof(TableAttribute)) as TableAttribute;  
        if (attr != null) {//说明类加了Table特性  
            tableName = attr.TableName;//取得表名  
        }  

        //sql语句模板:insert into Dept(deptno,dname,description) values('2','','');  
        StringBuilder sql = new StringBuilder("insert into ");  
        sql.Append(tableName);  
        sql.Append(" (");  

        //循环对象的属性名:取得列名  
        foreach (PropertyInfo item in obj.GetType().GetProperties()) {  
            //取得是否有自动增长的特性  
            IdentityAttribute att = Attribute.GetCustomAttribute(item, typeof(IdentityAttribute)) as IdentityAttribute;  
            if (att == null || !att.IsIdentity) {//没有,则添加列  
                sql.Append(item.Name);  
                sql.Append(",");  
            }  
        }  
        //去除最后一个逗号'  
        sql.Remove(sql.Length - 1, 1);  
        sql.Append(") values(");  
        //循环取出对象的属性值:为列赋值  
        foreach (PropertyInfo item in obj.GetType().GetProperties()) {  
            //取得是否有自动增长的特性  
            IdentityAttribute att = Attribute.GetCustomAttribute(item, typeof(IdentityAttribute)) as IdentityAttribute;  
            if (att == null) {//没有,则追加列的值  
                //GetValue():obj代表什么对象,null代表没有参数  
                sql.Append("'" + item.GetValue(obj, null) + "'");  
                sql.Append(",");  
            }  
        }  

        //去除最后一个逗号'  
        sql.Remove(sql.Length - 1, 1);  
        sql.Append(")");  
        //查看完整的sql语句  
        Console.WriteLine(sql.ToString());  

        //执行sql语句  
        SqlConnection conn = new SqlConnection("server=.;database=test;integrated security=true");  
        SqlCommand comm = new SqlCommand(sql.ToString(), conn);  
        conn.Open();  
        int r = comm.ExecuteNonQuery();  
        conn.Close();  

        return r;//返回执行结果  
    }  
}  
  /* 何问起 hovertree.com */
/****************测试类关键代码***************/  
Department dept = new Department("开发部", "负责产品的研发");  
ADOManager manager = new ADOManager();  
int r = manager.Save(dept);  

Console.WriteLine(r==0?"失败":"成功");  

小结:

C#的特性类和Java中的元注释同样

特征其本质就是多个卫冕了Attribute的类

采纳使能够大约Attribute结尾,如:TableAttribute =>> Table

天性将会影响其功效的目的成分的编写翻译和周转进度

行使自定义天性的步子:

  1. 概念天性类,类必须平昔或直接承继字Attribute类

  2. 在须求用的该个性的对象成分上增多性格

  3. 在动用增添了特征的类的行使,获取并选取自特定性子的音信

推荐:

网站地图xml地图