这样的事情可能吗?我假设没有,但对我来说很好看:
class MyClass {
public int Foo {
get { return m_foo; }
set {
// Bounds checking, or other things that prevent the use
// of an auto-implemented property
m_foo = value;
}
// Put the backing field actually *in* the scope of the property
// so that the rest of the class cannot access it.
private int m_foo;
}
void Method() {
m_foo = 42; // Can't touch this!
}
}
当然我知道这个语法不正确,这不会编译。为了清楚地描绘我的想法,这是假设的未来C#。我为这个有点假设性的问题道歉,但它对于Programmers.SE来说太具体了。
这样的东西可以在编译器中实现,它可以用于一个目的:只允许属性的get
和set
访问器查看该字段,基本上允许该属性是自包含的(如自动实现的属性是),同时允许额外的获取/设置逻辑。
答案 0 :(得分:31)
简短的回答是否定的,今天在C#中是不可能的。
我们经常收到这样的功能请求;它的更通用的形式是一个很好的功能。更通用的形式是更明确地使本地变量的生命周期与其范围正交。
只是为了确保这些条款是明确的:变量是一个存储位置,可能是名称。每个变量都有生存期:运行时保证变量引用有效存储的时间量。 名称的范围是可以使用该名称的文本区域;它是一个编译时的概念,而不是运行时概念。 local 变量是范围是语句块的变量。
在许多语言中,局部变量的生命周期与其范围密切相关:当控件在运行时逻辑上进入作用域时,生命周期开始,当它离开作用域时,生命周期结束。在C#中也是如此,有一些值得注意的警告:
如果运行时可以确定这样做对当前线程上托管代码的操作没有影响,则可以扩展或截断本地的生命周期。其他线程(如终结器线程)和当前线程上的非托管代码的操作是实现定义的。
可以扩展迭代器块,异步方法或匿名函数的封闭外部变量中的本地生存期,以匹配或超过迭代器,任务,委托的生命周期或使用它的表达式树。
显然,不是要求本地的生命周期和范围以任何方式捆绑在一起。如果我们可以明确地拥有具有实例或静态字段的生命周期的本地人,但是本地的范围,那将是很好的。 C有这个功能;你可以创建一个“静态”局部变量。 C#没有。您的提议主要是允许属性块中的局部变量具有实例的生命周期,但其范围仅限于块。
我会将此功能归类为“不错”。我们有一个潜在的“好”功能列表,只要你的手臂我们没有时间实现,所以我不希望这一个很快就能到达列表的顶部。谢谢你的反馈;它有助于我们在某种程度上优先考虑该列表。
答案 1 :(得分:6)
以下是我对此的看法:
public class WrappedField<T>
{
public class Internals
{
public T Value;
}
private readonly Internals _internals = new Internals();
private readonly Func<Internals, T> _get;
private readonly Action<Internals, T> _set;
public T Value
{
get { return _get(_internals); }
set { _set(_internals, value); }
}
public WrappedField(Func<Internals, T> get, Action<Internals, T> set)
{
_get = get;
_set = set;
}
public WrappedField(Func<Internals, T> get, Action<Internals, T> set, T initialValue)
: this(get, set)
{
_set(_internals, initialValue);
}
}
用法:
class Program
{
readonly WrappedField<int> _weight = new WrappedField<int>(
i => i.Value, // get
(i, v) => i.Value = v, // set
11); // initialValue
static void Main(string[] args)
{
Program p = new Program();
p._weight.Value = 10;
Console.WriteLine(p._weight.Value);
}
}
答案 2 :(得分:2)
根据C#4.0语言规范。
但是,与字段不同,属性不表示存储位置。 相反,属性具有指定语句的访问器 在读取或写入其值时执行。
添加字段需要内存位置。所以不,这是不可能的。
答案 3 :(得分:2)
如果您想避免使用泛型,您可以随时隐藏_backingField
和私有内部类中的边界检查。您甚至可以通过使外部类部分隐藏它来进一步隐藏它。当然,外部和内部类之间必须进行一些委托,这是一个无赖。代码解释我的想法:
public partial class MyClass
{
public int Property
{
get { return _properties.Property; }
set { _properties.Property = value; }
}
public void Stuff()
{
// Can't get to _backingField...
}
}
public partial class MyClass
{
private readonly Properties _properties = new Properties();
private class Properties
{
private int _backingField;
public int Property
{
get { return _backingField; }
set
{
// perform checks
_backingField = value;
}
}
}
}
但这是很多代码。为了证明所有锅炉板的合理性,最初的问题必须非常严重......
答案 4 :(得分:1)
不,可能属于该属性的唯一内容是get
和set
。
答案 5 :(得分:1)
嗯,处理起来相当困难,可能不是很有效,而不是我真正使用的东西,但从技术上来说,这是一种掩盖其他同学的支持领域的方法。
public class MySuperAwesomeProperty<T>
{
private T backingField;
private Func<T, T> getter;
private Func<T, T> setter;
public MySuperAwesomeProperty(Func<T, T> getter, Func<T, T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get
{
return getter(backingField);
}
set
{
backingField = setter(value);
}
}
}
public class Foo
{
public MySuperAwesomeProperty<int> Bar { get; private set; }
public Foo()
{
Bar = new MySuperAwesomeProperty<int>(
value => value, value => { doStuff(); return value; });
Bar.Value = 5;
Console.WriteLine(Bar.Value);
}
private void doStuff()
{
throw new NotImplementedException();
}
}