最近在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中,如果我将一个变量设置为一个闭包,我不会再次获得闭包,而不是它的结果吗?
答案 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_PropertyName
和set_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_name
和limbs
,就好像它们是原始字段一样,但它们只提供了替代语法调用相应的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);