C# 在C语言中优雅地处理重复的属性代码#

C# 在C语言中优雅地处理重复的属性代码#,c#,visual-studio,c#-4.0,properties,C#,Visual Studio,C# 4.0,Properties,语言捷径 public string Code { get; set; } 在C#中定义琐碎属性时节省了一点键入时间 然而,我发现自己编写的是高度重复的,而不是仍然遵循清晰模式的琐碎属性代码 public string Code { get { return code; } set { if (code != value) { code = value; NotifyPr

语言捷径

public string Code
{
    get;
    set;
}
在C#中定义琐碎属性时节省了一点键入时间

然而,我发现自己编写的是高度重复的,而不是仍然遵循清晰模式的琐碎属性代码

public string Code
{
    get { return code; }
    set 
    {
        if (code != value)
        {
            code = value; 
            NotifyPropertyChanged("Code");
        }
    }
}
我当然可以定义一个VisualStudio代码段来减少键入。然而,如果我需要向我的模式中添加一些东西,我必须返回并更改相当多的现有代码

有没有更优雅的方法?一个片段是最好的方法吗

更新:

作为目前的一个快速改进,我编辑了(备份后)

C:\Program Files\Microsoft Visual Studio 10.0\VC\Snippets\1033\Refactoring\EncapseField.snippet

(路径为VS 2010)


以反映我目前的模式。现在,内置重构工具使用my template从字段创建属性。缺点:Visual Studio的全局更改,无法追溯更改现有属性代码。

这是一种非常常见的模式。代码片段还可以,但是,如果MS为自动属性更改通知创建了一些语法糖,那岂不是太好了

public string Code { get; setwithnotify; }

那真是太好了。

我自己还没有做过,但是我已经看到一个依赖注入框架被用于这个特定的任务

谷歌和谷歌

啊哈

似乎可以使用将
INotifyPropertyChanged
注入自动属性。看看这篇很棒的博文:


这让我想起了最近的一次HanselMinutes,Scott正在和一个家伙谈论面向方面编程(AOP),这种类型的注入非常常见。

我讨厌编写这种代码


过去,为了解决这个问题,我实现了一个代码生成器,用属性定义生成一个
部分
类。最初灵感来源于乔恩·斯基特的作品


要回答有关重复代码的一般问题,而不仅仅是属性更改通知案例,请执行以下操作:

当然。对于宏来说,这是一个完美的例子

哦,等等。C#没有宏。当然,宏是邪恶的,并不是任何编程问题的最佳解决方案

除非在构建中插入预处理器。

这称为(AOP)

Scott Hanselman最近就这个话题采访了LinFu的创始人Philip Laureano。()

根据您的需要,有许多AOP工具

  • (团结的一部分)
最后,使用上述工具实现INotifyPropertyChanged类:

  • 后夏普
2013年更新:由于这个原始答案,我遇到了另一个解决方案,它可以非常轻松地完成我所需要的一切


(以前的NotifyPropertyWeaver)是一个编译后IL-weaver,它将自动为您插入属性更改代码。这是我现在首选的INotifyPropertyChanged解决方案。

感谢大家的回复。我对有用的答案投了赞成票。然而,经过相当多的研究,我开始相信最好的答案(至少对我和我开发软件的方式来说)是在VisualStudio中建模类,并使用T4代码生成实现属性代码的部分类


请参见

查看NotifyPropertyWeaver:

DI看起来非常有前途。虽然问题中没有说明,但我目前正在与Silverlight合作。不知道Unity2.0forSilverlight是否也支持这种模式(不知道与标准版相比,他们必须省略什么)。我自己过去也曾从UML模型生成代码。当项目“足够大”以保证基于模型的方法和代码生成器的创建时,这是一种很好的方法。随着建模工具越来越强大/集成,“足够大”的门槛不断降低。@Eric:就我个人而言,我会避免UML及其所有的智能开销。我认为您的目标很简单:具有属性的类在更改时通知。一个简单的解决方案可能是一个PowerShell脚本,它允许您编写:
class C{property string code;}
,并生成一个分部类。我以前也这样做过,当时我还想要一个流畅的类接口。这是一种使用扩展方法的有趣方法,尽管我没有完全遵循实现。“新{Title},Title”部分是做什么的?为什么不引用“值”呢?呵呵,它实际上是Jon Skeet在很久以前提出的,是在运行时获取属性名称的一种方法<代码>值没有被引用实际上是一个bug,因为它是从其他地方提出来的。我会修正它并扩展解决方案。谢谢你的澄清。当然是一个有趣的方法!是的,这将处理这个特定的模式,但是仍然没有解决重复某些任意模式的一般问题-理想情况下,可以插入对给定属性的修改。这不是答案,而是讨论,因此最好将其作为对原始问题的注释。除此之外,我认为将框架中的概念过多地嵌入C#语法不是一个好主意。一旦InotifyPropertyChange过时(只看依赖属性),我们就剩下一个遗留概念了。没有帮助(如果问题是在c++中,这甚至不是一个好的建议),这正是Jay Bazuzi所建议的,不是吗?NotifyPropertyWeaver已被弃用,取而代之的是NotifyPropertyWeaver。看见
public static class ObjectExtensions {
    public static string GetPropertyNameAndValue<T>(this T obj, out object value) {
        System.Reflection.PropertyInfo[] objGetTypeGetProperties = obj.GetType().GetProperties();
        if(objGetTypeGetProperties.Length == 1) {
            value = objGetTypeGetProperties[0].GetValue(obj, null);
            return objGetTypeGetProperties[0].Name;
        } else
            throw new ArgumentException("object must contain one property");
    }
}

class Whatever {
 protected void ChangeProperty<T>(object property, T newValue, Action change) {
     object value;
     var name = property.GetPropertyNameAndValue(out value);

     if(value == null && newValue != null || value != null && !value.Equals(newValue)) {
         change();
         OnPropertyChanged(name);
     }
 }

 private string m_Title;
 public string Title {
     get { return m_Title; }
     set {ChangeProperty(
               new { Title }, //This is used to dynamically retrieve the property name and value
               value, // new value
               () => m_Title = value); //lambda to change the value 
     }
 }
}
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>propfullinotify</Title>
            <Shortcut>propfullinotify</Shortcut>
            <Description>Code snippet for property and backing field with INotifyPropertyChanged</Description>
            <Author>Microsoft Corporation</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>type</ID>
                    <ToolTip>Property type</ToolTip>
                    <Default>int</Default>
                </Literal>
                <Literal>
                    <ID>property</ID>
                    <ToolTip>Property name</ToolTip>
                    <Default>MyProperty</Default>
                </Literal>
                <Literal>
                    <ID>field</ID>
                    <ToolTip>The variable backing this property</ToolTip>
                    <Default>myVar</Default>
                </Literal>
            </Declarations>
            <Code Language="csharp">
      <![CDATA[private $type$ $field$;

    public $type$ $property$
    {
        get { return $field$;}
        set {
      if ($field$ != value)
      {
        $field$ = value;
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("$property$"));
      }
    }
    }
    $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>