C# 自定义属性以确保封装
我开始研究自定义属性,我想到了以下想法:如果我可以创建一个属性,将变量的使用限制在它所支持的属性上,该怎么办C# 自定义属性以确保封装,c#,.net,attributes,C#,.net,Attributes,我开始研究自定义属性,我想到了以下想法:如果我可以创建一个属性,将变量的使用限制在它所支持的属性上,该怎么办 [RestrictToProperty("Foo")] private object _foo; public object Foo { get { return _foo; } set { _foo = value; OnFooChanged(EventArgs.Empty); } } public object NotF
[RestrictToProperty("Foo")]
private object _foo;
public object Foo
{
get { return _foo; }
set
{
_foo = value;
OnFooChanged(EventArgs.Empty);
}
}
public object NotFoo
{
get { return _foo; } // Warning
set { _foo = value; } // Warning
}
public void Bar()
{
_foo = new object(); // Warning
}
// Warning: 'MyClass._foo' should not be used outside of property 'Foo'
我相信这是可能的,因为过时的做了类似的事情
[Obsolete]
private object _foo;
public void Bar()
{
_foo = new object(); // Warning: 'MyClass._foo' is obsolete
}
不幸的是,我不知道该怎么做,除了简单的运行时属性教程之外,我找不到更多。这可能吗?如果是这样,我从哪里开始?您应该能够编写一条规则,使其成为错误或警告。不,这是不可能的ObsoleteAttribute
在C#规范中有一个关于编译器本身如何响应它的定义
可以通过使用隐式将变量的使用限制为单个属性
编辑:如果希望在getter和setter中独立处理特殊逻辑,可以尝试以下代码。这对我来说似乎非常讨厌
public class Test
{
private PrivateMembers Members { get; set; }
public object Foo
{
get
{
return Members.Foo;
}
set
{
Members.Foo = value;
// Do something else here.
}
}
private class PrivateMembers
{
public object Foo { get; set; }
}
}
不幸的是,这是不可能的。不过,您可能想探索一下,这是一个面向方面的.NET IL-weaver——基本上它让您的源代码经过一个额外的编译层,可以注入所有额外的仪式。稍微偏离主题,但您可以(ab)使用过时的
属性来实现您需要的功能
将支持字段标记为已过时,以便编译器在您尝试访问它时生成警告,然后在属性getter/setter中生成警告。(相关警告为和。)
这确实让人感觉像是一个令人讨厌的黑客行为,我真的不推荐这样做。还有其他更好的选择。例如,自定义FxCop规则、单元测试、良好的代码注释等。这令人失望。请参阅我对stakx关于自动实现属性的评论。@Daniel:我编辑了我的答案,以提供另一个令人讨厌的替代方案。我不确定这是如何实现我的目的的。。。如果没有Foo
属性,您仍然可以访问Members.Foo
,不是吗?@Daniel:是的,它肯定不能完全满足您的需要。+1表示完全相同的想法:)不幸的是,自定义FxCop规则可能与此非常接近(过时
的行为无法复制,除非你想编写自己的c#编译器)是的,我对它的破解并不感兴趣。我只是想知道我是否能想出一个优雅的解决方案。不过,谢谢你的想法。这是一个很好的例子,说明你能做什么。这其实很聪明。
public class Test
{
private PrivateMembers Members { get; set; }
public object Foo
{
get
{
return Members.Foo;
}
set
{
Members.Foo = value;
// Do something else here.
}
}
private class PrivateMembers
{
public object Foo { get; set; }
}
}
[Obsolete("Backing field should not be used outside of property")]
private object _foo;
public object Foo
{
#pragma warning disable 612, 618
get { return _foo; }
set
{
_foo = value;
OnFooChanged(EventArgs.Empty);
}
#pragma warning restore 612, 618
}