動態呼叫物件的屬性和方法 效能和靈活性兼備的方法

2022-01-12 20:39:31 字數 4195 閱讀 5511

在動態程式設計時,我們常常需要執行時確定呼叫物件的哪個屬性或哪個方法。這個任務通常可以用反射來解決。但眾所周知,反射的效能要比靜態指定的方式低很多,因為反射要通過執行時複雜的機制完成。能否獲得效能和靈活性兼備的動態呼叫?我在開發vbf的最新功能時反覆考慮了這個問題。我們通常動態呼叫乙個物件的屬性是採用這樣的手法,假設物件a有乙個屬性叫做myprop:

type t = a.gettype();

propertyinfo pi = t.getproperty("myprop");

string value = (string)pi.getvalue(a, null);

注意到什麼問題了嗎?我們知道這個屬性的型別是string,也知道它沒有引數。當然也有不知道即將呼叫的屬性型別及引數的時候,但這個場合我們知道,卻沒有利用,還是當成什麼資訊都不知道一樣使用純動態的手法獲取。這樣我們就錯失了能利用強型別特性加速這一過程的良機。同樣還有方法呼叫,我們有時候只是方法或屬性的名字在編譯時不知道(比如需要使用者指定),但方法或屬性的型別及簽名我們是知道的,這種情況下就可以用泛型和委託技術高效能地呼叫。

泛型技術為處理型別提供了方便,除此之外,.net的委託還具有一些額外的良好特性。委託可以擔當類似介面的任務,但與介面最大的不同就在於,方法無須宣告自己滿足某個委託,而只要簽名符合,即可賦給委託變數。這樣我們就可以利用一組事先宣告的委託,處理千變萬化型別的屬性與方法。

c#不允許屬性帶有引數,除非是索引器。vb允許屬性帶有引數但很少有人真的大量使用。於是在真實世界中屬性的getter和setter的形式就被限定了,絕大部分屬性的getter和setter可以用以下兩個委託表示:

public delegate void propertysetter(t value);

public delegate t propertygetter();

有了這兩個委託,我們就可以對已知型別但名字需要動態化的屬性進行高速的強型別動態訪問了。方法是使用反射獲取屬性gettet或setter的methodinfo,再使用methodinfo建立委託:

type t = a.gettype();

propertyinfo pi = t.getproperty("myprop");

methodinfo getter = pi.getgetmethod();

propertygetter strpropgetter =

(propertygetter)delegate.createdelegate(

typeof(propertygetter), a, getter);

string value = strpropgetter();

注意,這個方法在呼叫前進行了更多反射操作,因此,如果你只想一兩次地獲取屬性的值,這種方法還不如直接用放射來的快。但是,當你需要對同一屬性進行成千上萬次訪問時,絕對值得多寫這點**,在string型別的簡單屬性上,速度可比直接反射獲取最多快達1000倍,這是我實測的結果。

接下來我們討論有index的屬性和方法的呼叫。c#盡允許在索引器的語法上使用屬性引數,而在vb看來,索引器不過是類所有帶引數的屬性中比較特殊的乙個,他得到了在物件上使用陣列語法訪問的特權。不管怎麼說,無論是索引器還是普通帶引數的屬性,他們的getter和setter過程都不像典型屬性那樣簡單。同樣還有對方法的呼叫,方法的簽名千變萬化,似乎我們很難用預先定義的委託統一進行呼叫。事實的確如此,不過與針對每一種屬性訪問器或方法的簽名定義一種委託的做法相比,泛型還是給出了一種稍微舒服一點的做法:

public delegate r func();

public delegate r func(t0 a0);

public delegate r func(t0 a0, t1 a1);

public delegate r func(t0 a0, t1 a1, t2 a2);

這樣一組泛型委託,可以涵蓋引數數目從0-3,有返回值並且沒有引數是out或ref的所有方法簽名。你還可以定義一組用於無返回值的。有了這樣一組泛型委託,就可以在想要某種函式的簽名時直接建立出來,而無須宣告新的型別。再結合剛才的手法,就可以用統一的手法實現大部分帶有引數的屬性或方法的動態呼叫——同時獲得動態名稱和強型別效能的雙重好處。

也許你早已經利用了類似的手法,並用於除了動態呼叫屬性或方法以外的其他任務。我只是在開發vbf時想到了他們,希望能對部分需要的人有所幫助。

在動態程式設計時,我們常常需要執行時確定呼叫物件的哪個屬性或哪個方法。這個任務通常可以用反射來解決。但眾所周知,反射的效能要比靜態指定的方式低很多,因為反射要通過執行時複雜的機制完成。能否獲得效能和靈活性兼備的動態呼叫?我在開發vbf的最新功能時反覆考慮了這個問題。我們通常動態呼叫乙個物件的屬性是採用這樣的手法,假設物件a有乙個屬性叫做myprop:

type t = a.gettype();

propertyinfo pi = t.getproperty("myprop");

string value = (string)pi.getvalue(a, null);

注意到什麼問題了嗎?我們知道這個屬性的型別是string,也知道它沒有引數。當然也有不知道即將呼叫的屬性型別及引數的時候,但這個場合我們知道,卻沒有利用,還是當成什麼資訊都不知道一樣使用純動態的手法獲取。這樣我們就錯失了能利用強型別特性加速這一過程的良機。同樣還有方法呼叫,我們有時候只是方法或屬性的名字在編譯時不知道(比如需要使用者指定),但方法或屬性的型別及簽名我們是知道的,這種情況下就可以用泛型和委託技術高效能地呼叫。

泛型技術為處理型別提供了方便,除此之外,.net的委託還具有一些額外的良好特性。委託可以擔當類似介面的任務,但與介面最大的不同就在於,方法無須宣告自己滿足某個委託,而只要簽名符合,即可賦給委託變數。這樣我們就可以利用一組事先宣告的委託,處理千變萬化型別的屬性與方法。

c#不允許屬性帶有引數,除非是索引器。vb允許屬性帶有引數但很少有人真的大量使用。於是在真實世界中屬性的getter和setter的形式就被限定了,絕大部分屬性的getter和setter可以用以下兩個委託表示:

public delegate void propertysetter(t value);

public delegate t propertygetter();

有了這兩個委託,我們就可以對已知型別但名字需要動態化的屬性進行高速的強型別動態訪問了。方法是使用反射獲取屬性gettet或setter的methodinfo,再使用methodinfo建立委託:

type t = a.gettype();

propertyinfo pi = t.getproperty("myprop");

methodinfo getter = pi.getgetmethod();

propertygetter strpropgetter =

(propertygetter)delegate.createdelegate(

typeof(propertygetter), a, getter);

string value = strpropgetter();

注意,這個方法在呼叫前進行了更多反射操作,因此,如果你只想一兩次地獲取屬性的值,這種方法還不如直接用放射來的快。但是,當你需要對同一屬性進行成千上萬次訪問時,絕對值得多寫這點**,在string型別的簡單屬性上,速度可比直接反射獲取最多快達1000倍,這是我實測的結果。

接下來我們討論有index的屬性和方法的呼叫。c#盡允許在索引器的語法上使用屬性引數,而在vb看來,索引器不過是類所有帶引數的屬性中比較特殊的乙個,他得到了在物件上使用陣列語法訪問的特權。不管怎麼說,無論是索引器還是普通帶引數的屬性,他們的getter和setter過程都不像典型屬性那樣簡單。同樣還有對方法的呼叫,方法的簽名千變萬化,似乎我們很難用預先定義的委託統一進行呼叫。事實的確如此,不過與針對每一種屬性訪問器或方法的簽名定義一種委託的做法相比,泛型還是給出了一種稍微舒服一點的做法:

public delegate r func();

public delegate r func(t0 a0);

public delegate r func(t0 a0, t1 a1);

public delegate r func(t0 a0, t1 a1, t2 a2);

這樣一組泛型委託,可以涵蓋引數數目從0-3,有返回值並且沒有引數是out或ref的所有方法簽名。你還可以定義一組用於無返回值的。有了這樣一組泛型委託,就可以在想要某種函式的簽名時直接建立出來,而無須宣告新的型別。再結合剛才的手法,就可以用統一的手法實現大部分帶有引數的屬性或方法的動態呼叫——同時獲得動態名稱和強型別效能的雙重好處。

也許你早已經利用了類似的手法,並用於除了動態呼叫屬性或方法以外的其他任務。我只是在開發vbf時想到了他們,希望能對部分需要的人有所幫助。

C 動態呼叫類方法和屬性

var js new jiaoshi 建立類本身 type t js.gettype 反射出類的例項 object o activator.createinstance t system.reflection.propertyinfo pi t.getproperty xq id 獲得方法資訊 sy...

動態給物件新增屬性和方法

正常情況下,我們定義了乙個class,建立乙個class的例項後,我們可以給該例項繫結任何的屬性和方法,這就是動態語言的靈活性。動態給物件新增屬性和方法 class.屬性名 屬性值 class.方法名 函式 這裡說的動態加屬性和方法主要指的是關於 slots 函式的使用 slots 屬性名,函式名 ...

屬性和方法的呼叫

方法和屬性呼叫 同乙個類內部的呼叫特點 呼叫靜態屬性 方法時,本類類名可預設 屬性的呼叫 區域性屬性 直接使用屬性名呼叫 全域性屬性 static屬性 直接使用類名 屬性名呼叫 static string age 28 system.out.println test.age test是類名 clas...