全部,
我有一个 T4 模板,它生成样板代码,用于处理我的属性更改通知,并根据我分配给类的属性自动为我注册依赖属性。我使用 EnvDTE 在项目中上下移动并检索 ClassInfo 对象的 IEnumerable 来完成此操作。然后我通过 ClassInfo.Attributes 枚举以检索具有我创建的某些自定义属性(即 INotifyPropertyChangedAttributeAttribute:System.Attribute)的 ClassInfo 对象,以及我需要让模板为我编写样板代码的所有相关信息。
现在,我的问题是,是否可以(使用 EnvDTE)检查可能从基类继承的接口实现(例如 INotifyPropertyChanged),这样我的类中就不会出现两个 PropertyChanged 事件(一个在继承的类和代码生成的部分类中的一个)?
例如:
public class vmBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null) PropertyChanged(this, e);
}
}
[INotifyPropertyChangedAttribute(Test1, typeof(string))] //NOTE: By including this attribute, T4 template will automatically generate properties. What I need to know, though, is if the EnvDTE.ClassInfo can show Internface implementations as well so that I don't recreate the INotifyPropertyChanged Event
public partial class vm: vmBase //Implements INotifyPropertyChanged
{
//....
}
[INotifyPropertyChangedAttribute(Test2, typeof(string))]
public partial class SomeClassThatDoesNotImplementInotifyPropertyChangedAlready
{
//....
}
希望这是有道理的。
有关使用 envDTE 和 T4 处理依赖属性注册的示例,请参见http://www.scottlogic.co.uk/blog/colin/2009/08/declarative-dependency-property-definition-with-t4-dte/。我的项目中的概念是相同的,只是我正在调整它以处理 INotifyPropertyChanged 样板代码。
提前致谢。
我花了一点时间,但是是的 - 有一种方法可以通过 EnvDTE 找出给定的类是否以某种方式继承了给定的接口。
此代码片段仅检测直接从实现 INotifyPropertyChanged 的另一个类继承的类。所以在使用它之前,我们会在这里添加一些递归逻辑......
<#
// get a reference to the project of this t4 template
var project = VisualStudioHelper.CurrentProject;
// get all class items from the code model
var allClasses = VisualStudioHelper.GetAllCodeElementsOfType(project.CodeModel.CodeElements, EnvDTE.vsCMElement.vsCMElementClass, false);
// iterate all classes
foreach(EnvDTE.CodeClass codeClass in allClasses)
{
// get all interfaces implemented by this class
var allInterfaces = VisualStudioHelper.GetAllCodeElementsOfType(codeClass.ImplementedInterfaces, EnvDTE.vsCMElement.vsCMElementInterface, true);
if (allInterfaces.OfType<EnvDTE.CodeInterface>()
.Any(i => i.Name == "INotifyPropertyChanged"))
{
#>Implements Interface Directly: <#= codeClass.FullName #>
<#
// find classes that derive from this code class
foreach(EnvDTE.CodeClass potentialDerivingClass in allClasses)
{
IEnumerable<string> theBases = VisualStudioHelper.GetAllCodeElementsOfType(potentialDerivingClass.Bases, EnvDTE.vsCMElement.vsCMElementClass, true).OfType<EnvDTE.CodeClass>().Select(cc => cc.FullName);
if (theBases.Any(b => b == codeClass.FullName))
{
#>Derives from implementing class: <#= potentialDerivingClass.FullName #>
<#
}
}
}
}
#>
因此,假设实现 INotifyProperty 的类 A 发生了变化,从 A 派生的类 B 和从 B 派生的另一个类 C,此代码将提出实现 INotifyPropertyChanged 的类 A 和 B。
注意:因为使用 EnvDTE 类不是很好,所以我使用了一个名为“tangible Visual Studio Automation Helper”的 tangible T4 Editor 的免费模板库中的可重用模板 - 这使它更容易使用!
好的。愚蠢的问题,但究竟什么是 VisualStudioHelper。是从有形的吗?我使用的是 Tangible T4,但我借用了 Colin Eberhardt 的代码(请参阅相关链接)以通过 EnvDTE 进行枚举。
我应该注意到,当我查看图库中的有形 Visual Studio 自动化助手时,我看到的是 DTEHelper 类,而不是 VisualStudioHelper 类。DTEHelper 没有 GetAllCodeElementsOfType 函数。
好的。找到了。显然,有一个“Visual Studio Automation Helper”和一个“Tangible Visual Studio Automation Helper”。我在看前者。好的,我会试一试,看看我想出了什么。如果有效,那么我会将其标记为答案。
好的,那么现在另一个问题。这是否也会捕获我在基类中实现从 InterfaceB 继承的 InterfaceA 的实例?IE
public interface InterfaceA:INotifyPropertyChanged, SomeOtherInterface { } public class vmBase : InterfaceA { ... } public class vm : vmBase { ... }
还在 Tangible Visual Studio Automation Helper 中发现了一个错误。尝试多次转换模板,看看从自定义属性生成的部分类会发生什么。我将不得不深入研究模板,看看我是否可以识别错误以及如何修复它。话虽如此,我是 EnvDTE 的新手,所以对任何可以告诉我到底哪里出了问题以及如何修复它的人都投了赞成票。