簡體   English   中英

是否可以用 C# 以外的語言實現屬性?

[英]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

JavaScript 中

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_PropertyNameset_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 中是隱式的。如果tThingy ,則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_namelimbs ,就好像它們是原始字段一樣,但它們只是提供了一種替代語法來調用相應的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM