特性(Attribute)

前言:
本來打算將特性(Attribute)和反射(Reflection)寫在一章里,但感覺反射(Reflection)的內(nèi)容稍微有點(diǎn)點(diǎn)長敬察,所以新起一章秀睛,從學(xué)習(xí)順序方面,也是先學(xué)反射(Reflection)后學(xué)特性(Attribute)莲祸。

(官方文檔:https://docs.microsoft.com/zh-cn/dotnet/api/system.type?view=netframework-4.7.2

概念:
一蹂安、什么是特性(Attribute)?

CLR(common language runtime)允許你向程序的元素(programming elements)

(types(classes),結(jié)構(gòu)structs,字段fields,方法methods,屬性properties,委托delegates,事件Events,方法參數(shù)Params,方法返回值ReturnValue,泛型generic<xxx>參數(shù))

添加一些描述性的信息虫给,這些特性數(shù)據(jù)會(huì)和元數(shù)據(jù)(metadata)存放在一起藤抡,并通過反射(Reflection)技術(shù)運(yùn)行時(shí)獲取。

添加這些Attribute屬性的目的是實(shí)現(xiàn)一些豐富的功能抹估,比如在設(shè)計(jì)和調(diào)試階段使用Attribute特性來輔助開發(fā)缠黍。

我們?cè)谀繕?biāo)元素上應(yīng)用特性Attribute,會(huì)改變目標(biāo)的行為药蜻。比如FlagsAttribute瓷式,限定用于System.Enum枚舉類型,當(dāng)在Enum上應(yīng)用FlagsAttribute后语泽,在運(yùn)行時(shí)贸典,會(huì)通過反射Reflection檢測Enum是否使用了FlagsAttribute,如果使用踱卵,則會(huì)改變Enum的ToString和Format的行為.如果沒有廊驼,就視為一個(gè)普通的枚舉類型据过。

注:元數(shù)據(jù)(metadata)是用表來存儲(chǔ)的,程序集中會(huì)定義多個(gè)表妒挎,如類型定義表(types table),字段定義表(fields table)绳锅,方法定義表(methods table),屬性定義表(properties table)等等

.net framework出于各種原因酝掩,可以通過特性解決許多的問題鳞芙。
比如如何序列化和反序列化一個(gè)類或是字段[Serializable][NonSerialized],
提示用戶某些方法已經(jīng)或是將要被廢棄[Obsolete]期虾,
某些方法需要通過非拖管的代碼來實(shí)現(xiàn)[DllImport]原朝,
或是提供一些便利的操作...

二、常用的特性有哪些镶苞?

[Serializable]//序列化和反序列化喳坠,可以添加到類Class,結(jié)構(gòu)Struct,枚舉Enum,委托Delegate上宾尚,該特性不具有繼承性

[NonSerialized]//聲明某個(gè)字段Field不需要進(jìn)行序列化處理丙笋,也不具有繼承性,這通常是某些需要?jiǎng)討B(tài)進(jìn)行計(jì)算的值煌贴,比如說角色的總戰(zhàn)力

[DllImport]//聲明該方法使用非拖管代碼來實(shí)現(xiàn)御板,比如Unity3D開發(fā)當(dāng)中,與iOS進(jìn)行交互牛郑,調(diào)用iOS的API時(shí)怠肋,就需要使用該特性

[Obsolete]//聲明某個(gè)程序元素(program elements)將不會(huì)再使用了,準(zhǔn)備廢棄了,可以使用在某何程序元素上.

[Flags]//聲明枚舉被當(dāng)做一個(gè)位字段來處理(bit field),具體FlagsAttribute的解釋請(qǐng)看前面的文章”FlagsAttribute是什么?"

[AttributeUsage(AttributeTargets.Enum,Inherited=false)]//限制特定只能用于枚舉Enum上淹朋,并且不具有繼承性

[ParamArrayAttribute]//不定參數(shù)實(shí)際是一種特性Attribute,void test(params string[] val){...}

以上都是CLR預(yù)定義的特性笙各,可以根據(jù)需求自己實(shí)現(xiàn)"自定義"CustomAttribute特性.

三、特性Attribute的使用

特性Attribute實(shí)際上是一個(gè)類的實(shí)例础芍,必須直接或間接繼承自System.Attribute抽象類杈抢,CLR預(yù)定義的特性Attribute使用時(shí),大多數(shù)特性都需要引入命名空間:

using  System.Runtime.InteropServices;

特性可以定義在任意的命名空間中.

將特性Attribute應(yīng)用于目標(biāo)元素時(shí)仑性,相當(dāng)于調(diào)用了該特性Attribute類的實(shí)例構(gòu)造函數(shù)惶楼,下面是一些在目標(biāo)元素應(yīng)用特性Attribute的例子:

[Serializable]//目標(biāo)Person為可序列化和反序列化的類
    public class Person{
//...........
}


[NonSerialized]//字段name 不進(jìn)行序列化和反序列化
public string name;//Field

[OptionalField]//指定name字段為可選序列化,這通常用于可序列化的類中诊杆,新增成員時(shí)歼捐,要指定新增的成員是禁止序列化還是可選序列化,如果不添加晨汹,那么舊的序列化數(shù)據(jù)在進(jìn)行反序列化時(shí)豹储,會(huì)拋出異常,name無法被反序列化

public string name;//Field

[Flags]//在枚舉Vegetables上應(yīng)用Flags屬性淘这,改變枚舉的ToString和Format方法的行為
    public enum Vegetables
    {
        Cabbage = 1<<0,
        Carrot = 1<<1,
        Cuke = 1<<2,
        Potato = 1<<3,
    }

[DllImport("__Internal")]//在StartPayment方法上應(yīng)用DllImport剥扣,該方法由非拖管代碼實(shí)現(xiàn)巩剖,如Unity C#與iOS交互

public static extern void StartPayment(string paymentId,int bonusType);

在使用特性Attribute時(shí),我們可以添加一個(gè)前綴來指定要應(yīng)用于的目標(biāo)元素钠怯,許多時(shí)候球及,即使是省略前綴,編譯器也能判斷特性要應(yīng)用于什么目標(biāo)元素呻疹,如:

[type:Serializable]
    public class Person{
//...
}

[method:Obsolete]
public Person(string name,int age,bool married,float deposit)
{...}

[property:someAttr]
public string plan { ... }

[return:someAttr]
private string MarriedState(){...}
        
public static void SaySomething([param:someAttr] string words)
    

特性Attribute在使用時(shí),可以省略后面的Attribute筹陵,減少代碼量刽锤,提高可讀性,比如[Serializable]的全稱是[SerializableAttribute]

[Flags]=[FlagsAttribute]朦佩,但在使用中并思,我們不需要加上Attribute后綴,在自定義特性的時(shí)候语稠,我們需要加上宋彼,統(tǒng)一規(guī)范。

前面提到過仙畦,特性Attribute實(shí)際上是類的實(shí)例输涕,我們?cè)谑褂脮r(shí),傳遞的參數(shù)慨畸,是調(diào)用的該特性公共的構(gòu)造函數(shù)莱坎,在特性中Attribute中有兩種參數(shù):

1.定位參數(shù)(positional parameter),又叫必要參數(shù),即我們必須要傳遞的參數(shù)寸士,和調(diào)用常規(guī)的函數(shù)沒有區(qū)別檐什,按順序類型傳遞需要的參數(shù)即可,如:

[DllImport("__internal")] //DllImportAttribute特性類提供了一個(gè)接受string參數(shù)的構(gòu)造函數(shù)弱卡,傳遞了字符串__internal就是定位參數(shù)

2.命名參數(shù)(named parameter),又稱為可選參數(shù)乃正,他不是必需要設(shè)置的,通過命名參數(shù)來為特性Attribute類中的公共字段或?qū)傩赃M(jìn)行賦值婶博,如:

[DllImport("__internal"),CharSet=CharSet.Auto,SetLastError=true]
//CharSet和SetLastError是公共的實(shí)例字段或?qū)傩晕途撸ㄟ^命名參數(shù)來賦值

其它的,可以在目標(biāo)元素上同時(shí)應(yīng)用多個(gè)特性凡蜻,他們可分別在單獨(dú)的[](square bracket)中搭综,也可放在一個(gè)[](square bracket)中,并以逗號(hào)划栓,(comma)分離兑巾,并且和順序無關(guān),以下幾個(gè)都是等價(jià)的(只是演示不同的聲明形式忠荞,不考慮可行性):

[Obsolete][Serializable][Flags]
[Obsolete,Flags,Serializable]
[FlagsAttribute()][ObsoleteAttribute()][SerializableAttribute()]
[FlagsAttribute][ObsoleteAttribute][SerializableAttribute]

四蒋歌、定義自己的特性Attribute類

首先帅掘,定義自己的特性Attribute類,必須要直接或間接的從System.Attribute抽象類派生堂油,并且至少要包含一個(gè)公共的構(gòu)造函數(shù)修档,雖然特性類型是一個(gè)類,但這個(gè)類非常的簡單府框,除了提供公共的字段和屬性吱窝,他不應(yīng)該提供更多的公共方法,事件或其它的成員迫靖。通常建議使用屬性,而不是字段院峡,便于修改。

以FlagsAttribute特性為例:

namespace System.test{
    public class FlagsAttribute:System.Attribute{//派生自抽像類System.Attribute
        //至少提供一個(gè)公共的構(gòu)造函數(shù)
        public FlagsAttribute()
        {
        }
    }
}

有了特性Attribute類以后系宜,我們通常要限定特性的使用范圍照激,即可以在哪些目標(biāo)元素上使用,這就需要使用預(yù)定義的特性System.AttributeUsageAttribute盹牧。
這樣我們限制System.test.FlagsAttribute只能應(yīng)用于枚舉Enum:

namespace System.test{

    [AttributeUsage(AttributeTargets.Enum,Inherited=false)]
    public class FlagsAttribute:System.Attribute{//派生自抽像類System.Attribute
        //至少提供一個(gè)公共的構(gòu)造函數(shù)
        public FlagsAttribute()
        {
        }
    }
}

當(dāng)你在types,field,method,properties,events,delegates,returnvalue,params...上使用時(shí)俩垃,會(huì)出現(xiàn)編譯錯(cuò)誤。

AttributeUsage特性類很簡單汰寓,他提供了三個(gè)公共屬性口柳,分別是ValidOn,Inherited和AllowMultiple,ValidOn只能get,通過公共的構(gòu)造函數(shù)來set設(shè)置ValidOn,一個(gè)位標(biāo)志AttributeTargets.

ValidOn:應(yīng)用在哪些目標(biāo)元素上,可以通過位|(OR)組合有滑,應(yīng)用于多個(gè)目標(biāo)元素啄清。

AttributeTargets在FCL中的定義請(qǐng)查看官方文檔:
https://docs.microsoft.com/en-us/dotnet/api/system.attributetargets?view=netframework-4.7.2

Inherited:是否具有繼承性,比如你應(yīng)用在類上俺孙,如果Inherited=false辣卒,那么基類使用了該特性,派生類是不會(huì)繼承該特性的睛榄,比如說[Serializable]

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,Inherited=true)]
    public class StrongAttribute:System.Attribute{
        public StrongAttribute()
        {}
    }
        
    [Strong,Serializable]
    public class BaseClass{

        [Strong("Base")]
        public virtual void DoSomething(string v)
        {}
    }

    public class DerivedClass:BaseClass
    {
        public override void DoSomething(string v)
        {}
    }

BaseClass應(yīng)用了[Strong,Serializable]特性荣茫,DerivedClass派生自BaseClass,所以DerivedClass也繼承[Strong]特性,因?yàn)镮nherited=true场靴,但Derived并不能夠被序列化和反序列化啡莉,因?yàn)镾erializable特性類中Inherited=false

AllowMultiple:是否允許將特性多次應(yīng)用于同一個(gè)目標(biāo),通常來說是沒有意義的旨剥,比如[Flags][Flags]咧欣,重復(fù)定義,沒有實(shí)際作用轨帜,但有些特性還是需要的魄咕,比如條件特性類.

[Conditional("DEBUG")][Conditional("SANDBOX")]

只有在定義了DEBUG或SANDBOX符號(hào)的前提下,編譯器才會(huì)在元數(shù)據(jù)中生成特性信息蚌父。這個(gè)在設(shè)計(jì)和調(diào)試階段哮兰,那些用于輔助開發(fā)的特性非常有幫助毛萌,運(yùn)行中不需要的特性就不要加到元數(shù)據(jù)了,減少程序集的大小喝滞。

最后阁将,如果沒有指定AttributeUsage特性,那么會(huì)使用默認(rèn)值右遭,即可以使用在所有的目標(biāo)元素做盅,并且Inherited=true

五、檢測定制的特性Attribute
我自定義了特性Attribute并應(yīng)用在目標(biāo)元素上以后窘哈,我在運(yùn)行時(shí)言蛇,要進(jìn)行檢測是否使用了該特性,并執(zhí)行邏輯分支宵距。
比如枚舉應(yīng)用了Flags特性,那么我在調(diào)用ToString的時(shí)候吨拗,就要檢測當(dāng)前的枚舉是否應(yīng)用了Flags特性满哪,如:

public override string ToString ()
        {
            //檢測枚舉類型是否應(yīng)用了FlagsAttribute特性
            if (this.GetType ().IsDefined (typeof(FlagsAttribute), false)) {
                //接位標(biāo)志,以字符串的形式輸出
            } else {
                //當(dāng)成一個(gè)普通的枚舉值處理
            }
        }

通過調(diào)用Type的IsDefined方法劝篷,返回true哨鸭,表明該目標(biāo)元素應(yīng)用了特性。isDefined的第二個(gè)參數(shù)是Inherited娇妓,是否檢測特性的派生類像鸡,如果你只想檢測指定的類,那么額外的檢查是沒有必要的哈恰,可以將特性類設(shè)置為sealed密封類只估。

如果只是想檢測是否應(yīng)用了某個(gè)特性,使用IsDefined就可以了着绷,很高效蛔钙,不生成實(shí)例,但特性中我們可能會(huì)傳遞一些參數(shù)荠医,想要獲取這些特性的參數(shù)吁脱,就需要使用另外兩個(gè)靜態(tài)方法:

1.GetCustomAttributes()//返回目標(biāo)元素上應(yīng)用的所有特性,通常應(yīng)用于將AllowMultiple設(shè)置為true的特性彬向,一個(gè)特性多次用于同一個(gè)目標(biāo)元素上兼贡。

2.GetCustomAttribute()//返回目標(biāo)元素上應(yīng)用的指定的特性。
Retrieves a custom attribute of a specified type applied to an assembly, module, type member, or method parameter.

可以用于參數(shù)parameter和module以及assembly.
(文檔地址:https://docs.microsoft.com/en-us/dotnet/api/system.attribute.getcustomattribute?view=netframework-4.7.2)

獲取特性的實(shí)例這些操作是比較消耗的娃胆,從性能角度遍希,可以緩存這些方法的返回結(jié)果。

下面實(shí)現(xiàn)一個(gè)小例子里烦,現(xiàn)應(yīng)用GetCustomAttributes和GetCustomAttribute方法孵班。(來自于官方DEMO)

(官方文檔:https://docs.microsoft.com/en-us/dotnet/api/system.attribute.getcustomattribute?view=netframework-4.7.2#System_Attribute_GetCustomAttribute_System_Reflection_Module_System_Type_System_Boolean_)

// Define a custom parameter attribute that takes a single message argument.
[AttributeUsage( AttributeTargets.Parameter )]
public class ArgumentUsageAttribute : Attribute
{
    // This is the attribute constructor.
    public ArgumentUsageAttribute( string UsageMsg )
    {
        this.usageMsg = UsageMsg;
    }

    // usageMsg is storage for the attribute message.
    protected string usageMsg;

    // This is the Message property for the attribute.
    public string Message
    {
        get { return usageMsg; }
        set { usageMsg = value; }
    }
}

 public class BaseClass 
    {
        // Assign an ArgumentUsage attribute to the strArray parameter.
        // Assign a ParamArray attribute to strList using the params keyword.
        public virtual void TestMethod(
            [ArgumentUsage("Must pass an array here.")]
            String[] strArray,
            params String[] strList)
        { }
    }

    public class DerivedClass : BaseClass
    {
        // Assign an ArgumentUsage attribute to the strList parameter.
        // Assign a ParamArray attribute to strList using the params keyword.
        public override void TestMethod(
            String[] strArray,
            [ArgumentUsage("Can pass a parameter list or array here.")]
            params String[] strList)
        { }
    }

public void test()
        {
            Type t = typeof(DerivedClass);
            MethodInfo info = t.GetMethod ("TestMethod");
            ParameterInfo[] pInfoArray = info.GetParameters();
            foreach (var p in pInfoArray) {
                if (Attribute.IsDefined (p, typeof(ArgumentUsageAttribute))) {
                    ArgumentUsageAttribute usageAttr = (ArgumentUsageAttribute)
                        Attribute.GetCustomAttribute( 
                            p, typeof(ArgumentUsageAttribute) );

                    if (usageAttr != null) {
                        Debug.Log ("Usage:"+usageAttr.Message);
                        if (!p.ParameterType.IsArray) {
                            Debug.LogError ("You must set parameter to Array!");
                        }
                    }
                }
            }
        }


創(chuàng)建了一個(gè)特性Attribute類ArgumentUsage涉兽,默認(rèn)可繼承
又創(chuàng)建了一個(gè)BaseClass和DerivedClass派生類,
在基類的virtual方法中第一個(gè)參數(shù)加上特性 [ArgumentUsage("Must pass an array here.")],
因?yàn)锳rgumentUsage具有繼承性篙程,所以派生類DerivedClass中重載的方法的參數(shù)枷畏,
也繼承[ArgumentUsage("Must pass an array here.")],在派生類DerivedClass中又加入了 [ArgumentUsage("Can pass a parameter list or array here.")]特性,
那么在test2方法中虱饿,我通過反射Reflection來獲取方法TestMethod拥诡,并獲取參數(shù)是否應(yīng)用ArgumentUsage特性。

答案是Must pass an array here和Can pass a parameter list or array here都會(huì)輸出氮发。

下面加了一條判斷if (!p.ParameterType.IsArray)渴肉,判斷參數(shù)如果不是數(shù)組,則拋出異常爽冕。

(GetCustomAttributes的例子就不列了仇祭,返回目標(biāo)元素上的使用的特性數(shù)組。)

注:這里實(shí)測時(shí)在unity上有問題颈畸,在VS IDE上測試是正常通過乌奇,在unity下測試Derived中的string[] strArray并沒有繼承自父類BaseClass的參數(shù)的特性,初步斷定是framework的問題眯娱,畢竟u3d目前使用的mono版本還比較老礁苗,還存在一些問題,比如foreach徙缴,這個(gè)問題有知道的同學(xué)麻煩指點(diǎn)一下试伙,稍后會(huì)將該問題拋到stackoverflow上。
(stackoverflow問題地址:https://stackoverflow.com/questions/51351402/c-sharp-attribute-could-not-inherited-in-parameter-of-method)


到此為止,如果大家發(fā)現(xiàn)有什么不對(duì)的地方,歡迎指正,共同提高,感謝您的閱讀!

編輯于2018.7.15

--閑言碎語

今天是2018年的7月15日于样,世界杯決賽的日子疏叨,早上曼尼帕奎奧在第七回合TKO了對(duì)手,酣暢淋漓穿剖,晚上的世界杯決賽我支持克羅地亞考廉,世界杯讓我對(duì)莫德里奇有了新的認(rèn)識(shí),開始我是支持Brazil携御,支持保利尼奧昌粤,支持庫蒂尼奧,支持馬塞洛啄刹,可惜巴西在對(duì)陣比利時(shí)的比賽中涮坐,發(fā)揮得并不好,裁判也有爭議性的判罰誓军,很遺憾袱讹,法國一直踢得比較順利,所以希望今天克羅地亞可以給法國多制造一些麻煩,我希望莫德里奇拿到金球獎(jiǎng)捷雕!

61add42aly1ft8ga53g29j20i20muabh.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末椒丧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子救巷,更是在濱河造成了極大的恐慌壶熏,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浦译,死亡現(xiàn)場離奇詭異棒假,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)精盅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門帽哑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人叹俏,你說我怎么就攤上這事妻枕。” “怎么了粘驰?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵屡谐,是天一觀的道長。 經(jīng)常有香客問我晴氨,道長,這世上最難降的妖魔是什么碉输? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任籽前,我火速辦了婚禮,結(jié)果婚禮上敷钾,老公的妹妹穿的比我還像新娘枝哄。我一直安慰自己,他們只是感情好阻荒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布挠锥。 她就那樣靜靜地躺著,像睡著了一般侨赡。 火紅的嫁衣襯著肌膚如雪蓖租。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天羊壹,我揣著相機(jī)與錄音蓖宦,去河邊找鬼。 笑死油猫,一個(gè)胖子當(dāng)著我的面吹牛稠茂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播情妖,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼睬关,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼诱担!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起电爹,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤蔫仙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后藐不,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匀哄,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年雏蛮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涎嚼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挑秉,死狀恐怖法梯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情犀概,我是刑警寧澤立哑,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站姻灶,受9級(jí)特大地震影響铛绰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜产喉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一捂掰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧曾沈,春花似錦这嚣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至障涯,卻和暖如春罐旗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唯蝶。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工尤莺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人生棍。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓颤霎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子友酱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 問題 在2016年4月份做項(xiàng)目的時(shí)候遇到過一個(gè)問題晴音。 從BLE(低功耗藍(lán)牙)設(shè)備上收到數(shù)據(jù)(16進(jìn)制的數(shù)據(jù)流),<...
    AntonyWong閱讀 9,402評(píng)論 0 5
  • 先以一圖總結(jié): 以下:「attribute(s)」缔杉,「特性」是指同一事物(都指@property后面括號(hào)內(nèi)的單詞)...
    AntonyWong閱讀 13,564評(píng)論 9 47
  • 1锤躁、什么是Atrribute ******首先,我們肯定Attribute是一個(gè)類或详,下面是msdn文檔對(duì)它的描述:...
    func_老衲姓羅閱讀 2,007評(píng)論 0 2
  • 1系羞、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,980評(píng)論 3 119
  • 最近。 嗯霸琴,我很喜歡“最近”這詞椒振,這詞在我的文章里出現(xiàn)得頗多。 我屬于那類每隔一段時(shí)間梧乘,就會(huì)把零碎的事情“堆疊”澎迎,...
    郭栩鵬閱讀 314評(píng)論 2 3