是否可以用C#以外的语言实现属性?

时间:2009-03-23 20:43:04

标签: c# php javascript python properties

最近在C#和WPF的回合中,我开始喜欢C#的属性:

public double length_inches
{
    get { return length_metres * 39.0; }
    set { length_metres = value/39.0; }
}

当然注意到,length_metres可能会从字段变为属性,而代码无需关心。 WPF还可以非常愉快地将UI元素绑定到对象属性。

当我第一次了解类和对象时,我认为有一种方法可以做到,因为它看起来很明显!隐藏类中复杂性的关键在于您不再需要关心存储的内容。但直到现在才看到它。

有趣的是,我第一次看到它是在VB.Net中完成的。 OO纯度的前沿。

问题是,我可以重新使用我经常使用的其他语言的属性,比如javascript,python,php吗?在javascript中,如果我将一个变量设置为一个闭包,我不会再次获得闭包,而不是它的结果吗?

17 个答案:

答案 0 :(得分:19)

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

答案 1 :(得分:8)

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; }
};

答案 2 :(得分:6)

在C#中,属性主要只是一个编译器功能。编译器生成特殊方法get_PropertyNameset_PropertyName并计算出调用等等。它还设置了方法的specialname IL属性。

如果您选择的语言支持某种类型的预处理器,您可以实现类似的功能,但除此之外,您几乎不会遇到任何问题。

当然,如果您正在实现自己的.NET语言,那么您也可以执行C#编译器所做的事情。

由于实现细节,字段和属性之间实际上存在细微差别。有关详细信息,请参阅this question

答案 3 :(得分:4)

派生C#的Delphi具有go这个词的属性。大约15年前,这个词就是去了。

答案 4 :(得分:3)

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中创建一个非常好的伪造,创建一个与命名指南,受保护成员和魔术函数相结合的类。 Yuch。

答案 5 :(得分:3)

大多数动态语言支持类似的东西。在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 crash-course:@前缀表示它是一个实例变量。return隐含在Ruby中。t.length_inches = 42会自动调用length_inches=(42),如果{{1 }是t。)

如果您以后想要在getter / setter中添加一些逻辑,您只需手动实现相同的方法:

Thingy

答案 6 :(得分:2)

在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];
}

节省大量输入访问者的工作。

答案 7 :(得分:2)

Delphi有一个属性模式(使用Setter和Getter方法),也可以在接口中使用。具有“已发布”可见性的属性也将显示在IDE对象检查器中。

带有属性的类定义如下所示:

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;

答案 8 :(得分:2)

我认为这是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

答案 9 :(得分:1)

可悲的是,我还没有尝试过,但我读到可以通过__set和__get魔术方法在PHP中实现属性。这是关于这个主题的blog post

答案 10 :(得分:1)

绝对可以在其他语言中实现属性。例如,VB和F#具有显式属性支持。但这些都是针对具有财产支持的CLR。

VB。

Public Property Name As String 
  Get 
    return "someName"
  End Get
  Set
    ...
  End Set
End Property

我不相信javascript或PHP支持属性语法,但我不太熟悉这些语言。可以在几乎任何模拟属性的语言中创建字段get / set访问器方法。

在幕后,.Net属性实际上只会导致获取/设置方法。他们只有一个非常好的包装器:))

答案 11 :(得分:0)

您可以使用PHP5 magic functions制作类似的内容。

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;

答案 12 :(得分:0)

你可以用各种语言来做,不同程度的语法糖和魔法。如前所述,Python为此提供了支持(并且,使用装饰器你绝对可以清理它)。 PHP可以提供合理的传真与适当的__get()和__set()方法(可能是一些间接的。如果你正在使用Perl,你可以使用一些源过滤器来复制行为.Ruby已经要求一切都要经过

答案 13 :(得分:0)

当我第一次使用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”参数 - 它只是通过重载解析才能有效地作为函数名称的一部分。

现在,my_class的用户可以在很多情况下引用公共成员first_namelimbs,就好像它们是原始字段一样,但它们只提供了替代语法调用相应的get_property / set_property成员函数。

这并不完美,因为在某些情况下,只要编译器无法推断出所需的类型转换,就必须在属性上调用value()来获取值。此外,您可能会从this向构造函数中的成员传递警告,但在这种情况下您可以保持沉默。

答案 14 :(得分:0)

ActionScript 3(类固醇上的javascript)也有get / set语法

答案 15 :(得分:0)

Boo是一种非常类似于Python的.NET语言,但是使用静态类型。它可以实现属性:

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

答案 16 :(得分:-1)

约定是实现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);