是否可以用C#以外的语言实现属性?
在最近一次C#和WPF的较量中,我开始喜欢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
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_class
var 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