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

是否可以用C#以外的语言实现属性?,c#,php,javascript,python,properties,C#,Php,Javascript,Python,Properties,在最近一次C#和WPF的较量中,我开始喜欢C#的特性: public double length_inches { get { return length_metres * 39.0; } set { length_metres = value/39.0; } } class Foo(object): def get_length_inches(self): return self.length_meters * 39.0 def set_l

在最近一次C#和WPF的较量中,我开始喜欢C#的特性:

public double length_inches
{
    get { return length_metres * 39.0; }
    set { length_metres = value/39.0; }
}
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)
当然,请注意,length_meters可能会从字段变为属性,代码不必在意。WPF还可以非常愉快地将UI元素绑定到对象属性

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

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


问题是,我是否可以用其他更常用的语言(如javascript、python、php)重新创建属性?在javascript中,如果我将一个变量设置为一个闭包,我不会再次得到闭包,而不是它的结果吗

用其他语言实现属性绝对是可能的。例如,VB和F#具有明确的属性支持。但这两种方法都以具有属性支持的CLR为目标

VB

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

实际上,.Net属性只会产生get/set方法。它们只是有一个非常好的包装器:)

在C中,属性大多只是一个编译器特性。编译器生成特殊的方法
get\u PropertyName
set\u PropertyName
,并完成调用等。它还设置方法的
specialname
IL属性

如果您选择的语言支持某种类型的预处理器,那么您可以实现类似的东西,但除此之外,您几乎无法使用所获得的东西

当然,如果你正在实现自己的.NET语言,你也可以像C#编译器那样做


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

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

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

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

TFoo = class
private
  FBar: string;
  procedure SetBar(Value: string);
  function GetBar: string;

public
  property Bar: string read GetBar write SetBar;

end;
或(不带Setter/Getter):


Python绝对支持以下属性:

public double length_inches
{
    get { return length_metres * 39.0; }
    set { length_metres = value/39.0; }
}
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

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

ActionScript3(类固醇上的javascript)还有get/set语法

Delphi,C#就是从它派生而来的,它的属性来自go这个词。go这个词大约是15年前的事了。

遗憾的是,我自己还没有尝试过,但我读到可以通过u set和u get magic方法在PHP中实现属性。这里有一个关于这个主题的例子。

你可以做一些类似的事情这是我的


大多数动态语言都支持类似的功能。在Smalltalk和Ruby中,字段不是直接公开的-获取字段的唯一方法是通过方法。换句话说,所有变量都是私有的。Ruby有一些宏(类方法),以简化键入:

class Thing
  attr_accessor :length_inches
end
将为
length\u inches
生成一个getter和setter。在幕后,它只是生成以下内容:

class Thing
  def length_inches
    @length_inches
  end
  def length_inches=(value)
    @length_inches = value
  end
end
(Ruby速成课程:
@
前缀表示它是一个实例变量。
返回值在Ruby中是隐式的。
t.length\u inches=42
将自动调用
length\u inches=(42)
,如果
t
Thingy

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

class Thing
  def length_inches
    @length_metres * 39.0
  end
  def length_inches=(value)
    @length_metres = value / 39.0
  end
end
在:


您可以使用各种语言,使用不同程度的语法糖分和魔力来实现这一点。如前所述,Python为这一点提供了支持(并且,使用decorator,您肯定可以进一步清理它)。PHP可以使用适当的
\uu get()
\uu set()
方法提供合理的传真(可能是间接的。如果您使用Perl,您可以使用一些源代码过滤器来复制该行为。Ruby已经要求完成所有操作。

当我第一次使用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);
};
模板
类属性
{
城镇居民*业主;
公众:
物业(市民*业主)
:所有者{(所有者){}
TValue()常量
{
返回所有者->获取属性(TKey());
}
运算符TValue()常量
{
返回值();
}
TValue运算符=(const TValue&value)
{
所有者->设置属性(TKey(),值);
返回值;
}
};
上我的课
{
公众:
我的班级()
:名字(这个),四肢(这个){
结构{u k};
结构first_name_k{};
财产名称;
财产肢;
std::string get_属性(const first_name_k&);
void set_属性(const first_name_k&,const std::string&value);
int get_属性(const frameds_k&);
void set_属性(常数k&,int值);
};
请注意,“key”参数在
get\u property
/
set\u property
的实现中被忽略-它仅用于通过重载解析有效地作为函数名称的一部分

现在是
my_classvar object = {
  // .. other property definitions ...
  get length_inches(){ return this.length_metres * 39.0; },
  set length_inches(value){ this.length_metres = value/39.0; }
};
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);
};
Public Property Get LengthInches() As Double
  LengthInches = LengthMetres * 39
End Property

Public Property Let LengthInches(Value As Double)
  LengthMetres = Value / 39
End Property
@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];
}
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