如果需要自定义getter/setter,可以省略字段创建吗?

本文关键字:字段 创建 自定义 getter setter 如果 | 更新日期: 2023-09-27 18:16:13

我可以写出这样漂亮直接的代码:

 public int Delta { get; private set; }

现在我想添加一个调用OnPropertyChanged("Delta");

这是我知道的唯一方法:

public int Delta { get { return _delta; } private set
{
    _delta = value; OnPropertyChanged("Delta"); }
}
private int _delta;

额外代码太多了!为什么我要在这个例子中引入场?你能把这段代码写短一点吗?我想有这样的东西,但它不工作:

 public int Delta { get; private set { OnPropertyChanged("Delta"); } }

如果需要自定义getter/setter,可以省略字段创建吗?

不能使用auto-properties。自动属性是指字段上的属性的简写语法。他们实际上没有其他能力。任何自定义代码执行都需要一个完整的属性。

我为此创建了以下代码片段(示例):

private string _Name;
public string Name
{
    get { return _Name; }
    set
    {
        if (_Name != value) {
            _Name = value;
            OnPropertyChanged("Name");
        }
    }
}

片段:

<?xml version="1.0"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
      <Title>propn (Creates a notifying property)</Title>
      <Shortcut>propn</Shortcut>
      <Description>This snippet helps implementing INotifyPropertyChanged by creating a property with backing store. The settter calls OnPropertyChanged if the value changes. Use the "notify" code snippet in order to implement INotifyPropertyChanged.</Description>
      <Author>Olivier Jacot-Descombes</Author>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="false">
          <ID>classname</ID>
          <ToolTip>Name of class</ToolTip>
          <Default>ClassNamePlaceholder</Default>
          <Function>ClassName()</Function>
        </Literal>
        <Literal Editable="true">
          <ID>NameOfProperty</ID>
          <ToolTip>
          </ToolTip>
          <Default>MyProp</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>Type</ID>
          <ToolTip>
          </ToolTip>
          <Default>int</Default>
          <Function>
          </Function>
        </Literal>
      </Declarations>
      <Code Language="csharp"><![CDATA[private $Type$ _$NameOfProperty$;
public $Type$ $NameOfProperty$
{
    get { return _$NameOfProperty$; }
    set
    {
        if (_$NameOfProperty$ != value) {
            _$NameOfProperty$ = value;
            OnPropertyChanged("$NameOfProperty$");
        }
    }
}
]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

将此代码复制到文本文件中。给它一个扩展。"你可以使用代码片段管理器(工具菜单)将其导入到Visual Studio中。

下面是另一个创建事件处理程序的代码片段(示例):

#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
//TODO: Inherit interface System.ComponentModel.INotifyPropertyChanged.
//TODO: Create properties with the propn code snippet.
private void OnPropertyChanged(string propertyName)
{
    var handler = PropertyChanged;
    if (handler != null) {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
#endregion

片段:

<?xml version="1.0"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
      <Title>notify (Implements INotifyPropertyChanged)</Title>
      <Shortcut>notify</Shortcut>
      <Description>This snippet the inserts the INotifyPropertyChanged implementation into a class</Description>
      <Author>Olivier Jacot-Descombes</Author>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="false">
          <ID>classname</ID>
          <ToolTip>Name of class</ToolTip>
          <Default>ClassNamePlaceholder</Default>
          <Function>ClassName()</Function>
        </Literal>
      </Declarations>
      <Code Language="csharp"><![CDATA[#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
//TODO: Inherit interface System.ComponentModel.INotifyPropertyChanged.
//TODO: Create properties with the propn code snippet.
private void OnPropertyChanged(string propertyName)
{
    var handler = PropertyChanged;
    if (handler != null) {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
#endregion]]></Code>
    </Snippet>
  </CodeSnippet>
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>
      </Title>
      <Shortcut>
      </Shortcut>
      <Description>
      </Description>
      <Author>
      </Author>
    </Header>
    <Snippet>
      <Code Language="csharp"><![CDATA[]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

考虑它不是那么漂亮!参考Seeman的博客文章:Code Smell: Automatic Property

。NET属性是在底层生成的type get_PropertyName()set_PropertyName(type value)方法的语法糖,get_返回底层字段值,set_明显更新底层字段值。所以有两种选择:要么你通过指定属性getter/setter来提供自己的方法体,要么让框架为你生成支持字段,这样就没有第三种情况了。

如果你想简化你的PropertyChanged例程,你可以看看notifypropertyweaver

之后你的代码将看起来像:

[NotifyProperty(PerformEqualityCheck = false)]
public int Delta { get; set; }

不幸的是,情况就是这样。如果你使用的是c# 4.0,你可以使用动态对象,并且以牺牲类型安全为代价使用更少的代码。

简而言之

public override bool TrySetMember(SetMemberBinder binder, object value)
{
    //set the actual  property and do
    OnPropertyChanged(binder.Name);      
}
TrySetMember可能有更多的代码要写,但是你可以在同一个类的多个属性中共享它。

如果你不介意任何第三方框架,你可以使用AOP框架,如PostSharp,它为你做锅炉板代码。

不幸的是没有办法做到这一点。这种类型的构造在面向方面的编程中是可能的,但在c#编译器中迄今为止还没有任何生产版本。

没有通用的更好的方法来做到这一点,但你可以尝试使用像Resharpers snippets of VS snippets这样的模板引擎来更快地编写这些。

在某些情况下,当元数据可用时,您还可以使用代码生成来简化此操作。

自动属性是一个"全有或全无"的交易。

它们所做的只是创建一个后备字段,在get访问器中返回其值,并在set访问器中设置其值。如果您想做任何额外的事情,您必须定义支持字段并手动实现get和set。没有别的办法。

你可能想知道为什么你甚至需要一个自动属性,如果它没有任何逻辑?为什么不直接定义一个公共字段呢?但是,假设您定义了一个auto属性,并且其他程序集使用您的程序集。现在,如果您决定更改手动实现的属性以添加一些逻辑,则使用您的程序集的程序集不必重新编译。如果你从一个字段切换到一个属性,它们将中断,必须重新编译。

这里是我的交互式。net教程部分的直接链接,在那里我详细讨论了属性:http://motti.me/s2a

如果你感兴趣,这里是整个教程的链接:http://motti.me/c0

我希望这有助于!