C# 通过T4代码生成自动INotifyPropertyChanged实现?

C# 通过T4代码生成自动INotifyPropertyChanged实现?,c#,t4,inotifypropertychanged,C#,T4,Inotifypropertychanged,我目前正在建立一个新的项目,我想知道如何才能实现我的ViewModel类具有INotifyPropertyChanged支持,而不必自己编写所有属性的代码 我研究了AOP框架,但我认为它们只会用另一种依赖性来破坏我的项目 所以我考虑用T4生成属性实现 设置是这样的:我有一个ViewModel类,它只声明其属性背景变量,然后使用T4从中生成属性实现 例如,这将是我的ViewModel: public partial class ViewModel { private string p_So

我目前正在建立一个新的项目,我想知道如何才能实现我的ViewModel类具有INotifyPropertyChanged支持,而不必自己编写所有属性的代码

我研究了AOP框架,但我认为它们只会用另一种依赖性来破坏我的项目

所以我考虑用T4生成属性实现

设置是这样的:我有一个ViewModel类,它只声明其属性背景变量,然后使用T4从中生成属性实现

例如,这将是我的ViewModel:

public partial class ViewModel
{
    private string p_SomeProperty;
}
然后T4将检查源文件并查找名为“p_3;”的成员声明,并生成如下文件:

public partial class ViewModel
{
    public string SomeProperty
    {
        get
        {
            return p_SomeProperty;
        }
        set
        {
            p_SomeProperty= value;
            NotifyPropertyChanged("SomeProperty");
        }
    }
}

这种方法有一些优点,但我不确定它是否真的有效。因此,我想把我的想法作为一个问题发布在StackOverflow上,以获得一些反馈,或许还可以提供一些建议,让它做得更好/更容易/更安全。

它肯定会起作用

我建议首先编写一个实现
INotifyPropertyChanged
的基类,为它提供一个
受保护的void OnPropertyChanged(string propertyName)
方法,使它缓存其
PropertyChangeEventArgs
对象(每个唯一的属性名一个,每次引发事件时创建一个新对象没有意义),并让您的T4生成类从此基础派生

要实现需要属性的成员,只需执行以下操作:

BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
FieldInfo[] fieldsNeedingProperties = inputType.GetFields(flags)
    .Where(f => f.Name.StartsWith("p_"))
    .ToArray();
从这里开始:

<# foreach (var field in fieldsNeedingProperties) { #>
<# string propertyName = GetPropertyName(field.Name); #>
    public <#= field.FieldType.FullName #> <#= propertyName #> {
        get { return <#= field.Name #>; }
        set {
            <#= field.Name #> = value;
            OnPropertyChanged("<#= propertyName #>");
        }
    }
<# } #>

<#+
    private string GetPropertyName(string fieldName) {
        return fieldName.Substring(2, fieldName.Length - 2);
    }
#>

公开的{
获取{return;}
设置{
=价值;
不动产变更(“”);
}
}
等等。

通过使用EnvDTE直接从Visual Studio检查自定义属性,从T4生成依赖项属性。由于post包含浏览代码节点的简单实用方法,因此调整它以检查字段并适当地生成代码应该不难


请注意,从VS使用T4时,您不应在自己的程序集上使用反射,否则它们将被锁定,您必须重新启动Visual Studio才能重建。

有很多方法可以剥除这只猫的皮肤

我们一直在玩弄PostSharp来注入INotifyProperty样板文件。看起来效果不错

尽管如此,T4没有理由不起作用

我同意Dan的观点,您应该创建OnPropertyChanged的基类实现

您是否考虑过只使用代码片段?它将为您编写样板文件。唯一的缺点是,如果您希望在以后某个日期更改属性名称,它将不会自动更新

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>propin</Title>
      <Shortcut>propin</Shortcut>
      <Description>Code snippet for property and backing field with support for INotifyProperty</Description>
      <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>
      </Declarations>
      <Code Language="csharp">
        <![CDATA[private $type$ _$property$;

    public $type$ $property$
    {
        get { return _$property$;}
        set 
    {
      if (value != _$property$)
      {
        _$property$ = value;
        OnPropertyChanged("$property$");
      }
    }
    }
    $end$]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

丙酸
丙酸
支持INotifyProperty的属性和支持字段的代码段
膨胀
类型
属性类型
int
财产
属性名
我的财产



我觉得自己像个白痴,但我不知道T4是什么,直到因为这个问题才在谷歌上搜索到它。我真不敢相信这件事居然没被提起!我也是。我是从一个有一年历史的C#预处理器线程()中得到的。Doh.see也是T4的一个更简单的替代方法,我使用Visual Studio宏来避免编写属性的公共定义。我有更多关于如何创建VS宏的信息,还有一些示例宏,可以在@Rachel中使用PropertyChange通知自动构建公共属性:宏不是从VS2012中删除的吗?我认为这不再是一个选项。反射不是一个真正的选项(见朱利安·勒博斯奎因的回答)。@chrischu:如果你这么说的话。在我看来,完全排除反思对于每堂课只需要做一次的事情来说有点过激。我以前曾多次使用这种技术为我编写课程,当时我不想做这么多打字工作。因此,您必须在之后重新启动Visual Studio。这很糟糕吗?是的,我考虑过使用代码片段。然而,使用代码片段仍然比使用T4(当它最终起作用时…)需要更多的工作。我看了PostSharp,但问题是我不想在我的项目中有更多的依赖项。这是真的。但是,在我看来,我们在这个模式上花费了很多精力,只是因为我们讨厌它,而且它很丑陋。但这并不难理解或维持。添加属性和OnPropertyChanged样板需要5秒钟。那么,有什么比2-3行重复代码或对PostSharp或某些钝T4的依赖更好呢?每个属性有2-3行重复代码。总而言之。此外,通过生成的代码使OnPropertyChanged调用,OnPropertyChanged(“SomeProperty”)对于拼写错误不安全的问题可以自动克服,而不会受到运行时性能的影响(如通过反射)。这是一种折衷。我想说的是,在项目的整个生命周期中,2-3行代码将更容易维护。这是个人喜好:-p这很甜蜜。我对模板进行了调整,以生成自定义类型描述符。保存了数千行代码。请注意,从VS2010 SP1开始,锁定问题已经解决,因此现在可以使用反射。