[英]Is it possible to implement properties in languages other than C#?
在最近的一次 C# 和 WPF 中,我喜歡 C# 的屬性:
public double length_inches
{
get { return length_metres * 39.0; }
set { length_metres = value/39.0; }
}
當然,請注意,length_metres 可能會從一個字段變為一個屬性,並且代碼不需要關心。 WPF 還可以非常愉快的將 UI 元素綁定到 object 屬性。
當我第一次了解類和對象時,我認為有辦法做到這一點,因為它看起來很明顯。 在 class 中隱藏復雜性的關鍵在於您不再需要關心存儲的內容。 但直到現在才看到它。
有趣的是,我第一次看到它是在 VB.Net 中完成的。 OO 純度的領先優勢。
問題是,我可以用其他更常用的語言重新創建屬性,例如 javascript、python、php? 在 javascript 中,如果我將一個變量設置為閉包,我不會再次獲得閉包,而不是它的結果嗎?
Python 絕對支持屬性:
class Foo(object):
def get_length_inches(self):
return self.length_meters * 39.0
def set_length_inches(self, val):
self.length_meters = val/39.0
length_inches = property(get_length_inches, set_length_inches)
從 Python 2.5 開始,存在用於只讀屬性的語法糖,在 2.6 中也存在可寫屬性:
class Foo(object):
# 2.5 or later
@property
def length_inches(self):
return self.length_meters * 39.0
# 2.6 or later
@length_inches.setter
def length_inches(self, val):
self.length_meters = val/39.0
var object = {
// .. other property definitions ...
get length_inches(){ return this.length_metres * 39.0; },
set length_inches(value){ this.length_metres = value/39.0; }
};
在 C# 中,屬性大多只是編譯器功能。 編譯器生成特殊方法get_PropertyName
和set_PropertyName
並計算出調用等等。 它還設置方法的specialname
IL 屬性。
如果你選擇的語言支持某種預處理器,你可以實現類似的東西,但否則你幾乎會被你所擁有的東西所困。
當然,如果您正在實現自己的 .NET 語言,您也可以執行 C# 編譯器所做的事情。
由於實現細節,字段和屬性之間實際上存在細微差別。 有關詳細信息,請參閱此問題。
Delphi 是 C# 的派生詞,它具有來自單詞 go 的屬性。 而 go 這個詞大約是 15 年前的事了。
大多數動態語言都支持類似的東西。 在 Smalltalk 和 Ruby 中,字段不直接暴露 - 獲得它們的唯一方法是通過方法。 換句話說 - 所有變量都是私有的。 Ruby 有一些宏(實際上是類方法),以使其更易於鍵入:
class Thing
attr_accessor :length_inches
end
將為length_inches
創建一個 getter 和一個 setter。 在幕后,它只是生成這個:
class Thing
def length_inches
@length_inches
end
def length_inches=(value)
@length_inches = value
end
end
(Ruby 速成課程: @
前綴表示它是一個實例變量。 return
在 Ruby 中是隱式的。如果t
是Thingy
,則t.length_inches = 42
將自動調用length_inches=(42)
。)
如果您稍后想要在 getter/setter 中添加一些邏輯,您可以簡單地手動實現相同的方法:
class Thing
def length_inches
@length_metres * 39.0
end
def length_inches=(value)
@length_metres = value / 39.0
end
end
在 VB(即 VB 6.0,不是 VB.net)和 VBScript 中開箱即用!
Public Property Get LengthInches() As Double
LengthInches = LengthMetres * 39
End Property
Public Property Let LengthInches(Value As Double)
LengthMetres = Value / 39
End Property
也可以在 PHP 中很好地偽造,創建一個 class,您可以結合命名准則、受保護的成員和魔術函數進行擴展。 呵呵。
Delphi 有一個屬性模式(帶有 Setter 和 Getter 方法),也可以在接口中使用。 具有“已發布”可見性的屬性也將顯示在 IDE object 檢查器中。
具有屬性的 class 定義如下所示:
TFoo = class
private
FBar: string;
procedure SetBar(Value: string);
function GetBar: string;
public
property Bar: string read GetBar write SetBar;
end;
或(沒有 Setter / Getter):
TFoo = class
private
FBar: string;
public
property Bar: string read FBar write FBar;
end;
我認為這是 Python 等價物
class Length( object ):
conversion = 39.0
def __init__( self, value ):
self.set(value)
def get( self ):
return self.length_metres
def set( self, value ):
self.length_metres= value
metres= property( get, set )
def get_inches( self ):
return self.length_metres*self.conversion
def set_inches( self, value ):
self.length_metres= value/self.conversion
inches = property( get_inches, set_inches )
它是這樣工作的。
>>> l=Length(2)
>>> l.metres
2
>>> l.inches
78.0
>>> l.inches=47
>>> l.metres
1.2051282051282051
在 Objective-C 2.0 / Cocoa 中:
@interface MyClass : NSObject
{
int myInt;
NSString *myString;
}
@property int myInt;
@property (nonatomic, copy) NSString *myString;
@end
然后在實現中,只需指定:
@synthesize myInt, myString;
這將為該成員變量生成具有鍵值編碼兼容命名約定的訪問器,例如:
- (void)setMyString:(NSString *)newString
{
[myString autorelease];
myString = [newString copy];
}
節省大量輸入訪問器的工作。
絕對可以用其他語言實現屬性。 例如,VB 和 F# 具有顯式屬性支持。 但是這些都針對具有屬性支持的CLR。
VB。
Public Property Name As String
Get
return "someName"
End Get
Set
...
End Set
End Property
我不相信 javascript 或 PHP 支持屬性語法,但我對這些語言不是很熟悉。 幾乎可以用任何模擬屬性的語言創建字段獲取/設置訪問器方法。
在引擎蓋下,.Net 屬性實際上只是歸結為 get/set 方法。 他們只是有一個非常好的包裝:)
ActionScript 3(類固醇上的javascript)也有get/set語法
遺憾的是,我自己還沒有嘗試過,但我讀到可以通過 __set 和 __get 魔術方法在 PHP 中實現屬性。 這是有關此主題的博客文章。
您可以使用PHP5 魔術函數制作類似的東西。
class Length {
public $metres;
public function __get($name) {
if ($name == 'inches')
return $this->metres * 39;
}
public function __set($name, $value) {
if ($name == 'inches')
$this->metres = $value/39.0;
}
}
$l = new Length;
$l->metres = 3;
echo $l->inches;
你可以用各種語言來做,有不同程度的語法糖和魔法。 如前所述,Python 提供了對此的支持(並且,使用裝飾器,您絕對可以進一步清理它)。 PHP could provide a reasonable facsimile with appropriate __get()
and __set()
methods (probably some indirection to. If you're working with Perl, you could use some source filters to replicate the behaviour. Ruby already requires everything to go through.
當我第一次使用 Visual Basic(比如版本 1 或其他東西)時,我做的第一件事就是嘗試在 C++ 中重新創建屬性。 可能在當時我可以使用模板之前,但現在它會是這樣的:
template <class TValue, class TOwner, class TKey>
class property
{
TOwner *owner_;
public:
property(TOwner *owner)
: owner_(owner) {}
TValue value() const
{
return owner_->get_property(TKey());
}
operator TValue() const
{
return value();
}
TValue operator=(const TValue &value)
{
owner_->set_property(TKey(), value);
return value;
}
};
class my_class
{
public:
my_class()
: first_name(this), limbs(this) {}
struct limbs_k {};
struct first_name_k {};
property<std::string, my_class, first_name_k> first_name;
property<int, my_class, limbs_k> limbs;
std::string get_property(const first_name_k &);
void set_property(const first_name_k &, const std::string &value);
int get_property(const limbs_k &);
void set_property(const limbs_k &, int value);
};
請注意,在get_property
/ set_property
的實現中忽略了“key”參數 - 它只是通過重載解析有效地充當 function 名稱的一部分。
現在my_class
的用戶將能夠在許多情況下引用公共成員first_name
和limbs
,就好像它們是原始字段一樣,但它們只是提供了一種替代語法來調用相應的get_property
/ set_property
成員函數。
這並不完美,因為在某些情況下,當編譯器無法推斷所需的類型轉換時,您必須在屬性上調用 value() 才能獲取值。 此外,您可能會因為將this
傳遞給構造函數中的成員而收到警告,但在這種情況下您可以將其靜音。
Boo是一種 .NET 語言,與 Python 非常相似,但使用 static 類型。 它可以實現屬性:
class MyClass:
//a field, initialized to the value 1
regularfield as int = 1 //default access level: protected
//a string field
mystringfield as string = "hello"
//a private field
private _privatefield as int
//a public field
public publicfield as int = 3
//a static field: the value is stored in one place and shared by all
//instances of this class
static public staticfield as int = 4
//a property (default access level: public)
RegularProperty as int:
get: //getter: called when you retrieve property
return regularfield
set: //setter: notice the special "value" variable
regularfield = value
ReadOnlyProperty as int:
get:
return publicfield
SetOnlyProperty as int:
set:
publicfield = value
//a field with an automatically generated property
[Property(MyAutoProperty)]
_mypropertyfield as int = 5
約定是實現一個get_PropertyName()
和一個set_PropertyName()
方法(這也是 CLR 中的全部內容。屬性只是 VB.NET/C# 中的語法糖 - 這就是為什么從字段更改為屬性或反之反之亦然,需要重新編譯客戶端代碼。
public int get_SomeValue() { return someValue; }
public void set_SomeValue(int value) { someValue = value; }
private int someValue = 10;
// client
int someValue = someClass.get_SomeValue();
someClass.set_SomeValue(12);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.