软件的程序代码的生成方法及装置
技术领域
本发明涉及计算机领域,具体而言,涉及一种软件的程序代码的生成方法及装置。
背景技术
依赖属性是软件开发中应用的重要手段之一,设计依赖属性的目的就是根据多个不同的输入动态计算出属性值,这些不同的输入包括:资源文件、绑定、动画、属性继承等,现有技术对于依赖属性的定义通常采取如下部分代码:
从上述代码可知,定义依赖属性非常繁琐,每次定义都要手动输入大量内容,但是从中可以发现规律,即除了上述斜体字,其他的字符都是固定不变的,现有技术中解决的方案比如visual studio或Resharper等工具都可以在界面上自动生成上述固定不变的字符串,即在IsSpinning或bool等依赖属性的属性值上采用斜体等特殊方式标识。用户只需针对有特殊标识的属性值进行输入,以解决上述输入繁琐的问题。
这里需要说明的是,上述代码中多次重复出现依赖属性名称,例如,IsSpinning,用户每次在修改依赖属性的都要多次进行重复的输入,最后生成依赖属性的代码,代码生成效率较低。
针对现有技术在生成具有重复部分的代码时,需要针对重复的部分手动依次输入,导致生成代码效率低的问题,目前尚未提出有效的解决方案。
发明内容
本发明的主要目的在于提供一种软件的程序代码的生成方法和装置,以解决现有技术在生成具有重复部分的代码时,需要针对重复的部分手动依次输入,导致生成代码效率低的问题。
为了实现上述目的,根据本发明实施例的一个方面,提供了一种软件的程序代码的生成方法,该方法包括:定义标记类并将标记类应用到程序集中的目标类中,生成新的程序集,其中,标记类用于标记目标类的属性特征,目标类为实现目标功能的程序代码;通过T4模板和DTE来获取新的程序集中标记类中的每个对象中的属性值;将标记类中的每个对象中的属性值替换目标代码模板中的占位符,生成目标代码,其中,目标代码模板为预先定义的模板;将目标代码输出到程序集中的目标类中。
为了实现上述目的,根据本发明实施例的另一方面,提供了一种代码生成的装置。该装置包括:第一定义单元,定义标记类并将标记类应用到程序集中的目标类,生成新的程序集,其中,标记类用于标记目标类的属性特征,目标类为实现目标功能的程序代码;获取单元,用于通过T4模板和DTE来获取新的程序集中标记类中的每个对象中的属性值;替换单元,用于将标记类中的每个对象中的属性值替换目标代码模板中的占位符,生成目标代码,其中,目标代码模板为预先定义的模板;输出单元,用于将目标代码输出到程序集中的目标类中
根据发明实施例,通过定义标记类;将标记类应用到程序集中的目标类中,生成新的程序集,其中,标记类用于标记目标类的属性特征,目标类为实现目标功能的程序代码;通过T4模板和DTE来获取新的程序集中标记类中的每个对象中的属性值;将标记类中的每个对象中的属性值替换目标代码模板中的占位符,生成目标代码,其中,目标代码模板为预先定义的模板;将目标代码输出到程序集中的目标类中,本发明解决了现有技术在生成具有重复部分的代码时,需要针对重复的部分手动依次输入,导致生成代码效率低的问题。
附图说明
构成本申请的一部分的附图用来提供对本发明的进一步理解,本发明的示意性实施例及其说明用于解释本发明,并不构成对本发明的不当限定。在附图中:
图1是根据本发明实施例一的代码生成方法的流程图;
图2是根据本发明实施例一的优选的代码生成方法的示意图;
图3是根据本发明实施例一的优选的代码生成方法的示意图;
图4是根据本发明实施例二的代码生成装置的结构示意图;
图5是根据本发明实施例二的优选的代码生成装置的结构示意图;以及
图6是根据本发明实施例二的优选的代码生成装置的示意图。
具体实施方式
需要说明的是,在不冲突的情况下,本申请中的实施例及实施例中的特征可以相互组合。下面将参考附图并结合实施例来详细说明本发明。
为了使本技术领域的人员更好地理解本发明方案,下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分的实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都应当属于本发明保护的范围。
需要说明的是,本发明的说明书和权利要求书及上述附图中的术语“第一”、“第二”等是用于区别类似的对象,而不必用于描述特定的顺序或先后次序。应该理解这样使用的数据在适当情况下可以互换,以便这里描述的本发明的实施例。此外,术语“包括”和“具有”以及他们的任何变形,意图在于覆盖不排他的包含,例如,包含了一系列步骤或单元的过程、方法、系统、产品或设备不必限于清楚地列出的那些步骤或单元,而是可包括没有清楚地列出的或对于这些过程、方法、产品或设备固有的其它步骤或单元。
本申请应用术语解释如下:
1.Visual Studio:是微软为开发人员提供的开发工具。
2.Resharper:是Visual Studio的一个插件,主要是提供很多便利的功能,提高开发效率。
3.T4模板:集成在Visual Studio中代码生成工具,主要用于自动生成代码。
4.分部类:就是将类拆分到多个文件中,每个文件是类的一部分,编译时将所有部分组合起来。
5.分部方法:类似于分部类,就是将方法拆分到多个文件中,一个文件中给出方法定义,一个文件中给出方法实现。
6.Attribute(特性):在.NET中定义的类、方法都是有元数据的,以类为例,类的名称、类型、命名空间,访问修饰符(public、private)这些都相当于元数据信息,编译好的程序集包含这些元数据信息。特性也是一种元数据信息,编译后程序集中保存了每个类应用的特性。
7.反射:就是读取程序集的元数据,运行时创建类的实例,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了特性,可以利用反射来访问它们。
8.工程:代码组织方式,可以理解为存放代码容器,可以包含文件夹、代码文件、XML文件、文本文件等。
9.解决方案:同样是一种代码组织方式,比工程范围更广,一个解决方案包含多个工程,还可以包含虚拟文件夹(因为解决方案中的文件夹不是真实存在的,不对应具体真实文件路径,工程中的文件夹是对应真实的文件路径的)。
10.DTE,开发环境,其实就是Visual Studio提供的编程接口,使用这些接口可以针对Visual Studio进行编程,扩展Visual Studio的功能。
实施例1
本发明实施例提供一种软件的程序代码的生成方法,如图1所示,该方法可以包括:
步骤S101,定义标记类,并将标记类应用到程序集中的目标类,生成新的程序集,其中,标记类用于标记目标类的属性特征,目标类为实现目标功能的程序代码。
具体的,本实施例可以以生成依赖属性的模板的代码为例进行描述,本实施例提供的方法可以首先定义上述标记类,上述标记类可以是DenpendencyPropertyAttribute,上述标记类可以包含对象,上述对象可以是依赖属性的至少一个特征,上述标记类DependencyProperyAttribute则包含上述依赖属性的至少一个特征。可选的,可以将定义的标记类应用到需要生成依赖属性的程序集中,具体应用到程序集中需要生成依赖属性的目标类中,上述程序集由于添加了标记类因而生成新的程序集。
步骤S103,通过T4模板和DTE来获取新的程序集中标记类中的每个对象中的属性值。
步骤S105,将标记类中的每个对象中的属性值替换目标代码模板中的占位符,生成目标代码,其中,目标代码模板为预先定义的模板。
具体的,上述目标代码模板可以为生成依赖属性的模板,例如下面的代码:
在上述代码中,占位符0、1、2、3可以对应上述标记类的4个属性。从上述模板中可以看到第零个占位符为依赖属性的名称,第一个占位符为依赖属性的类型,第二个占位符为依赖属性的拥有者,第三个占位符为依赖属性的默认值。读取到每个类的DependencyPropertyAttribute的四个属性值后,直接将上述四个占位符替换即可。
步骤S107,将目标代码输出到程序集中的目标类中。
可选的,在新的程序集中生成依赖属性代码之后,如果要修改依赖属性的话,只需要修改DependencyProperyAttribute的四个属性值即可,不需要多处修改。比如以下的依赖属性的定义:
如果用户想修改依赖属性的名称,用户只需要上述代码中的斜字"IsSpinning"即可,程序集中所有依赖属性的名称都会自动随着改变,如果用户想在程序集里添加依赖属性的时候,也不需要对多个重复的属性值进行多次添加。只需要添加一处就可以了。
本实施例通过定义标记类,并将标记类应用到程序中的目标类,通过T4模板和DTE来获取上述标记类中的属性值,添加到预先定义的目标代码的模板中,从而生成目标代码,上述目标代码中包含重复的部分。本实施例解决了现有技术在生成具有重复部分的代码时,需要针对重复的部分手动依次输入,导致生成代码效率低的问题。
可选的,步骤S101中定义标记类的步骤还可以包括:
步骤S201,定义标记类的对象,其中,标记类的对象包括至少一个属性,在生成依赖属性的实例中,上述至少一个属性可以是:名称、类型、拥有者和默认值。
具体的,上述标记类可以是DependencyPropertyAttribute,上述DependencyPropertyAttribute可以包含依赖属性的四个特征定义如下表1:
表1:
PropertyName |
依赖属性的名称 |
Type |
依赖属性的类型 |
Owner |
依赖属性的拥有者 |
DefaultValue |
依赖属性的默认值 |
可选的,步骤S101中的定义标记类并将标记类应用到程序集中的目标类,生成新的程序集之前,本实施例提供的方法还可以包括:
步骤S301,接收用户输入的参数,在标记类中生成属性值,其中,参数分别对应 标记类的对象。
具体的,用户可以输入参数,上述参数可以是用户希望在上述目标类中生成的依赖属性代码中的至少一个属性值,例如,下面的这个例子:
可选的,步骤S103中通过T4模板和DTE来获取新的程序集中标记类中的每个对象中的属性值的步骤还可以包括:
步骤S401,获取T4模板所在的工程。
步骤S402,递归遍历工程中的应用了标记类的目标类。
步骤S403,获取标记类中每个对象的属性值。
可选的,步骤S401中的获取T4模板所在的工程的步骤还可以包括:
步骤S501,获取T4模板在模板转换引擎中的宿主。
具体的,结合图2所示,在运行T4模板之后,本实施例提供的方法可以先获取T4模板所在模板转换引擎的宿主,由于T4模板不能独立运行,需要寄宿在某个进程中,寄宿的进程可以称为宿主,宿主一般为VisualStudio,也可以使用其他的可执行程序来寄宿T4模板。
步骤S502,使用宿主获取DTE。
具体的,当宿主为VisualStudio的时候,可以使用上述宿主来获取DTE,此时相当于获取了VisualStudio对象,使用上述对象可以访问VisualStudio的多种功能。
步骤S503,使用DTE获取T4模板所在的工程。
可选的,上述DTE提供了Solution属性,可以使用该属性的FindProjectItem方法即可获取T4模板所在的工程。
可选的,步骤S402中的递归遍历工程中的应用了标记类的目标类的步骤可以包括:
步骤S601,遍历工程下所有工程项目。
步骤S602,循环遍历工程项目中的代码项目。
具体的,结合图2,本实施例可以通过递归遍历获取上述工程中所有应用了DenpendencyPropertyAttribute的类项目。本实施例提供的方法可以先循环遍历上述T4模板所在工程下的所有工程项目,对于每个工程项目,可以循环遍历工程项目中的代码项目,这里需要说明的是,每个工程项目对应一个源文件,每个源文件可以包含多个代码项目,比如,一个源文件中可以同时定义两个类,即可以包含两个类项目。
步骤S603,递归遍历每个代码项目并将所有代码项目组建一个集合。
具体的,本实施例提供的方法可以递归管理每个代码项目,将所有代码项目都添加到项目集合中。
步骤S604,对集合筛选出含有应用了标记类的目标类。
具体的,本实施例提供的方法可以将收集到的所有代码项目,并对上述代码项目进行筛选,筛选出所有应用了DenpendencyPropertyAttribute的类项目。
这里需要说明的是,结合图3,递归流程操作如下:首先将当前代码项目添加到集合中,然后,判断是否有子项目,如果有的话,循环遍历代码项目,重复第1步操作;如果没有递归结束。
可选的,结合图6,在本实施例中递归遍历工程中的应用了标记类的目标类之后,本实施例提供的方法还可以包括:
步骤S10,获取目标类中应用的所有Attribute的项目
步骤S20,筛选出应用的所有DenpendencyPropertyAttribute,如果Attribute项目的Name属性为DenpendencyPropertyAttribute,即应用了DenpendencyPropertyAttribute。
步骤S30,获取上述目标类中每个DenpendencyPropertyAttribute的各个属性值,对于上面Ispinning的定义,Attribute项目的Value属性即为如下字符串:PropertyName=“Ispinning”,Type=“bool”,Owner=“ExampleClass”,DefaultValue=false,在获取到上述字符串后,对字符串进行解析即可得到各个属性的定义,具体过程如下:先使用逗号拆分字符串,即得到各个属性赋值片段,然后对每个片段使用等号分隔,第一部分即为各个属性的值,生成依赖属性只需要使用得到的属性填充上述依赖属性模板即可。
可选的,步骤S105,将标记类应用到程序集中的目标类,生成新的程序集之前,本发明实施例提供的方法还可以包括:
步骤S1031,使用T4模板定义目标代码模板,其中,在生成依赖属性的实例中,目标代码模板中可以包含以下至少一个属性:名称、类型、拥有者和默认值,其中,名称、类型、拥有者和默认值在目标代码模板中使用不同的占位符替换。
可选的,本实施例相对于旧的技术方案,为修改依赖属性提供了便利,说明了如何简化依赖属性的生成和修改,但是该解决方案并不局限于依赖属性,比如下面的例子也可以使用该解决方案解决:
这个例子中CustomerId属性的生成,和依赖属性的生成同属一类问题,即需要输入许多内容,但是这些内容大部分都是重复的,只有一小部分内容是不一样的。这个属性的生成也可以通过Visual Studio和Resharper提供的功能实现,但是问题和依赖属性的问题是一样的,即不支持修改。使用该解决方案,也可以解决类似于这样的属性的生成。
下面本申请结合具体场景进行描述:
1.首先定义DependencyPropertyAttribute特性,这个特性包含了依赖属性的四个特征定义,如下表2:
PropertyName |
依赖属性的名称 |
Type |
依赖属性的类型 |
Owner |
依赖属性的拥有者 |
DefaultValue |
依赖属性的默认值 |
2.在每个定义依赖属性的类上应用DependencyPropertyAttribute,并指定依赖属性的上述四个特征,比如下面的这个例子:
3.使用T4模板和DTE(可以理解为Visual Studio对外提供的API,用来扩展VisualStudio的功能)遍历所有使用了DependencyPropertyAttribute的类项目,根据这些类项目中DependencyPropertyAttribute的定义,为这些类生成依赖属性的定义,具体逻辑如图2所示。
(1)获取T4模板所在工程。
a.首先,获取T4模板所在模板转换引擎的宿主,T4模板不能独立运行,需要寄宿在某个进程中,寄宿的进程称为宿主,宿主一般为Visual Studio。也可以开发自己的可执行程序,用来寄宿T4模板。
b.此时我们的宿主就是Visual Studio,因此使用宿主获取DTE,此时相当于获取了Visual Studio对象,使用这个对象可以访问Visual Studio的诸多功能。
c.使用DTE获取T4模板所在的工程。
此处需要说明的是,上述DTE提供了Solution属性,使用该属性的FindProjectItem方法即可获取T4模板所在工程。
(2)通过递归遍历获取这个工程中所有应用了DependencyPropertyAttribute的类项目。
a.循环遍历工程下的所有工程项目,对于每个工程项目,循环遍历当前工程项目的代码项目。
此处需要说明的是,上述每个工程项目对应一个源文件,每个源文件可以包含多个代码项目,比如一个源文件中可以同时定义两个类,即包含两个类项目。
b.递归遍历每个代码项目,将所有代码项目都添加到项目集合中。
c.此时收集到所有代码项目,对这些项目进行筛选,筛选出所有应用了DependencyPropertyAttribute的类项目。
具体的,上述递归操作流程结合图3所示:
首先,将当前代码项目添加到集合中。
然后,判断是否有子项目,如果有的话,循环遍历代码项目,重复第1步操作;如果没有递归结束。
(3)获取应用的所有DependencyPropertyAttribute,为每个应用了DependencyPropertyAttribute的类生成依赖属性定义,具体流程结合图6所示:
a.获取这个类应用的所有Attribute项目
b.筛选出应用的所有DependencyPropertyAttribute,如果Attribute项目的Name属性为DependencyPropertyAttribute,即应用了DependencyPropertyAttribute
c.获取每个DependencyPropertyAttribute各个属性值,对于上面IsSpinning的定义,Attribute项目的Value属性即为如下字符串:PropertyName="IsSpinning",Type="bool",Owner="ExampleClass",DefaultValue="false",在获取到这个字符串后,对字符串进行解析即可得到各个属性的定义,具体过程如下:先使用逗号拆分字符串,即得到各个属性赋值片段,然后对每个片段使用等号分隔,第一部分即为属性名称,第二部分提出双引号即为属性值,此时就得到各个属性的值,生成依赖属性只需要使用得到的属性值填充下面的模板即可
依赖属性的模板如下:
从模板中可以看到第零个占位符为依赖属性的名称,第一个占位符为依赖属性的类型,第二个占位符为依赖属性的拥有者,第三个占位符为依赖属性的默认值。读取到每个类的DependencyPropertyAttribute的四个属性值后,直接将上述四个占位符替换即可。
如果要修改依赖属性的定义的话,只需要修改DependencyPropertyAttribute的属性即可,不需要多处修改。比如下面的依赖属性定义:
如果用户想修改依赖属性的名称,只需要修改标红的文字就可以了,不需要多处修改。当然添加依赖属性定义的时候,也只需要添加一处就可以了。
在上面的依赖属性的模板中,定义了IsSpinningPropertyChangeCallback的分部方 法,如果类需要定义这个回调函数的话,只需要实现这个分部方法就可以了
综上,本申请的发明点在于可以使用T4模板和DTE自动生成依赖属性,再递归遍历所有应用了DependencyPropertyAttribute的类项目,本申请相对于旧的技术方案,新技术方案为修改依赖属性提供了便利。
虽然这里给出的解决方案,说明了如何简化依赖属性的生成和修改,但是该解决方案并不局限于依赖属性,比如下面的例子也可以使用该解决方案解决:
这个例子中CustomerId属性的生成,和依赖属性的生成同属一类问题,即需要输入许多内容,但是这些内容大部分都是重复的,只有一小部分内容是不一样的。这个 属性的生成也可以通过Visual Studio和Resharper提供的功能实现,但是问题和依赖属性的问题是一样的,即不支持修改。使用该解决方案,也可以解决类似于这样的属性的生成。
实施例2
本发明实施例还提供了一种软件的程序代码的生成装置,如图4所示:
该装置可以包括:
第一定义单元601,用于定义标记类并将标记类应用到程序集中的目标类,生成新的程序集,其中,标记类用于标记目标类的属性特征,目标类为实现目标功能的程序代码。
具体的,本实施例可以以生成依赖属性的模板的代码为例进行描述,本实施例提供的方法可以首先定义上述标记类,上述标记类可以是DenpendencyPropertyAttribute,上述标记类可以包含对象,上述对象可以是依赖属性的至少一个特征,上述标记类DependencyProperyAttribute则包含上述依赖属性的至少一个特征。可选的,将定义的标记类应用到需要生成依赖属性的程序集中,具体应用到程序集中需要生成依赖属性的目标类中,上述程序集由于添加了标记类因而生成新的程序集。
获取单元603,用于通过T4模板和DTE来获取新的程序集中标记类中的每个对象中的属性值。
替换单元604,用于将标记类中的每个对象中的属性值替换目标代码模板中的占位符,生成目标代码,其中,目标代码模板为预先定义的模板。
具体的,上述目标代码模板可以为依赖属性的模板,例如下面的代码:
在上述代码中,占位符0、1、2、3可以对应上述标记类的4个属性。从上述模板中可以看到第零个占位符为依赖属性的名称,第一个占位符为依赖属性的类型,第二个占位符为依赖属性的拥有者,第三个占位符为依赖属性的默认值。读取到每个类的DependencyPropertyAttribute的四个属性值后,直接将上述四个占位符替换即可。
输出单元605,用于将目标代码输出到程序集中的目标类中。
可选的,在新的程序集中生成依赖属性代码之后,如果要修改依赖属性的话,只需要修改DependencyProperyAttribute的四个属性值即可,不需要多处修改。比如以下的依赖属性的定义:
如果用户想修改依赖属性的名称,用户只需要上述代码中的斜字"IsSpinning"即可,程序集中所有依赖属性的名称都会自动随着改变,同理,在程序集里添加依赖属性的时候,也不需要对多个重复的属性值进行多次添加。只需要添加一处就可以了。
本实施例通过定义标记类,将标记类应用到程序中的目标类,通过T4模板和DTE来获取上述标记类中的属性值,添加到预先定义的目标代码的模板中,从而生成目标代码,上述目标代码中包含重复的部分。本实施例解决了现有技术要生成具有重复部分的代码要针对重复的部分手动依次输入,生成代码效率低的问题。
可选的,上述第一定义单元601可以包括:
定义模块701,用于定义标记类的对象,其中,在生成依赖属性的实例中,标记类的对象包括至少一个属性,在生成依赖属性的实例中,上述至少一个属性可以是:名称、类型、拥有者和默认值。
具体的,上述标记类可以是DependencyPropertyAttribute,上述DependencyPropertyAttribute可以包含依赖属性的四个特征定义如下表3:
表3:
PropertyName |
依赖属性的名称 |
Type |
依赖属性的类型 |
Owner |
依赖属性的拥有者 |
DefaultValue |
依赖属性的默认值 |
可选的,本发明实施提供的装置还可以包括:
接收单元801,用于接收用户输入的参数,在标记类中生成属性值,其中,参数分别对应标记类的对象。
具体的,用户可以输入参数,上述参数可以是用户希望在上述目标类中生成的依赖属性代码中的至少一个属性值,例如,下面的这个例子:
可选的,如图5所示,上述获取单元603还可以包括:
第一获取模块701,用于获取T4模板所在的工程。
遍历模块702,用于递归遍历工程中的应用了标记类的目标类。
第二获取模块703,用于获取标记类中每个对象的属性值。
可选的,上述第二获取模块703还可以包括:
第一子获取模块7031,用于获取T4模板在模板转换引擎中的宿主。
具体的,结合图2所示,在运行T4模板之后,本实施例提供的方法可以先获取T4模板所在模板转换引擎的宿主,由于T4模板不能独立运行,需要寄宿在某个进程中,寄宿的进程可以称为宿主,宿主一般为VisualStudio,也可以使用其他的可执行程序来寄宿T4模板。
第二子获取模块7032,用于使用宿主获取DTE。
具体的,当宿主为VisualStudio的时候,可以使用上述宿主来获取DTE,此时相 当于获取了VisualStudio对象,使用上述对象可以访问VisualStudio的多种功能。
第三子获取模块7033,用于使用DTE获取T4模板所在的工程。
可选的,上述DTE提供了Solution属性,可以使用该属性的FindProjectItem方法即可获取T4模板所在的工程。
具体的,上述遍历模块702还可以包括:
第一子遍历模块7021,用于遍历工程下所有工程项目。
第二子遍历模块7022,用于循环遍历工程项目中的代码项目。
具体的,结合图2,本实施例可以通过递归遍历获取上述工程中所有应用了DenpendencyPropertyAttribute的类项目。本实施例提供的方法可以先循环遍历上述T4模板所在工程下的所有工程项目,对于每个工程项目,可以循环遍历工程项目中的代码项目,这里需要说明的是,每个工程项目对应一个源文件,每个源文件可以包含多个代码项目,比如,一个源文件中可以同时定义两个类,即可以包含两个类项目。
第三子遍历模块7023,用于递归遍历每个代码项目并将所有代码项目组建一个集合。
具体的,本实施例提供的方法可以递归管理每个代码项目,将所有代码项目都添加到项目集合中。
筛选模块7024,用于对集合筛选出含有应用了标记类的目标类。
具体的,本实施例提供的方法可以将收集到的所有代码项目,并对上述代码项目进行筛选,筛选出所有应用了DenpendencyPropertyAttribute的类项目。
这里需要说明的是,结合图3,递归路程操作如下:首先将当前代码项目添加到集合中,然后,判断是否有子项目,如果有的话,循环遍历代码项目,重复第1步操作;如果没有递归结束。
可选的,本实施例提供的装置还可以包括:
第二定义单元801,用于使用T4模板定义目标代码模板,其中,目标代码模板中包含以下至少一个属性:名称、类型、拥有者和默认值,其中,名称、类型、拥有者和默认值在目标代码模板中使用不同的占位符替换。
可选的,本实施例相对于旧的技术方案,为修改依赖属性提供了便利,说明了如何简化依赖属性的生成和修改,但是该解决方案并不局限于依赖属性,比如下面的例子也可以使用该解决方案解决:
这个例子中CustomerId属性的生成,和依赖属性的生成同属一类问题,即需要输入许多内容,但是这些内容大部分都是重复的,只有一小部分内容是不一样的。这个属性的生成也可以通过Visual Studio和Resharper提供的功能实现,但是问题和依赖属性的问题是一样的,即不支持修改。使用该解决方案,也可以解决类似于这样的属性的生成。
下面本申请结合具体场景进行描述:
1.首先定义DependencyPropertyAttribute特性,这个特性包含了依赖属性的四个特征定义,如下表4:
表4:
PropertyName |
依赖属性的名称 |
Type |
依赖属性的类型 |
Owner |
依赖属性的拥有者 |
DefaultValue |
依赖属性的默认值 |
2.在每个定义依赖属性的类上应用DependencyPropertyAttribute,并指定依赖属性的上述四个特征,比如下面的这个例子:
3.使用T4模板和DTE(可以理解为Visual Studio对外提供的API,用来扩展VisualStudio的功能)遍历所有使用了DependencyPropertyAttribute的类项目,根据这些类项目中DependencyPropertyAttribute的定义,为这些类生成依赖属性的定义,具体逻辑如图2所示。
(1)获取T4模板所在工程。
a.首先,获取T4模板所在模板转换引擎的宿主,T4模板不能独立运行,需要寄宿在某个进程中,寄宿的进程称为宿主,宿主一般为Visual Studio。也可以开发自己的可执行程序,用来寄宿T4模板。
b.此时我们的宿主就是Visual Studio,因此使用宿主获取DTE,此时相当于获取了Visual Studio对象,使用这个对象可以访问Visual Studio的诸多功能。
c.使用DTE获取T4模板所在的工程。
此处需要说明的是,上述DTE提供了Solution属性,使用该属性的FindProjectItem方法即可获取T4模板所在工程。
(2)通过递归遍历获取这个工程中所有应用了DependencyPropertyAttribute的类项目。
a.循环遍历工程下的所有工程项目,对于每个工程项目,循环遍历当前工程项目的代码项目。
此处需要说明的是,上述每个工程项目对应一个源文件,每个源文件可以包含多个代码项目,比如一个源文件中可以同时定义两个类,即包含两个类项目。
b.递归遍历每个代码项目,将所有代码项目都添加到项目集合中。
c.此时收集到所有代码项目,对这些项目进行筛选,筛选出所有应用了DependencyPropertyAttribute的类项目。
具体的,上述递归操作流程结合图3所示:
首先,将当前代码项目添加到集合中。
然后,判断是否有子项目,如果有的话,循环遍历代码项目,重复第1步操作;如果没有递归结束。
(3)获取应用的所有DependencyPropertyAttribute,为每个应用了DependencyPropertyAttribute的类生成依赖属性定义,具体流程结合图6所示:
a.获取这个类应用的所有Attribute项目
b.筛选出应用的所有DependencyPropertyAttribute,如果Attribute项目的Name属性为DependencyPropertyAttribute,即应用了DependencyPropertyAttribute
c.获取每个DependencyPropertyAttribute各个属性值,对于上面IsSpinning的定义,Attribute项目的Value属性即为如下字符串:PropertyName="IsSpinning",Type="bool",Owner="ExampleClass",DefaultValue="false",在获取到这个字符串后,对字符串进行解析即可得到各个属性的定义,具体过程如下:先使用逗号拆分字符串,即得到各个属性赋值片段,然后对每个片段使用等号分隔,第一部分即为属性名称,第二部分提出双引号即为属性值,此时就得到各个属性的值,生成依赖属性只需要使用得到的属性值填充下面的模板即可
依赖属性的模板如下:
从模板中可以看到第零个占位符为依赖属性的名称,第一个占位符为依赖属性的类型,第二个占位符为依赖属性的拥有者,第三个占位符为依赖属性的默认值。读取到每个类的DependencyPropertyAttribute的四个属性值后,直接将上述四个占位符替换即可。
如果要修改依赖属性的定义的话,只需要修改DependencyPropertyAttribute的属性即可,不需要多处修改。比如下面的依赖属性定义:
如果用户想修改依赖属性的名称,只需要修改标红的文字就可以了,不需要多处修改。当然添加依赖属性定义的时候,也只需要添加一处就可以了。
在上面的依赖属性的模板中,定义了IsSpinningPropertyChangeCallback的分部方法,如果类需要定义这个回调函数的话,只需要实现这个分部方法就可以了
综上,本申请的发明点在于可以使用T4模板和DTE自动生成依赖属性,再递归遍历所有应用了DependencyPropertyAttribute的类项目,本申请相对于旧的技术方案,新技术方案为修改依赖属性提供了便利。
虽然这里给出的解决方案,说明了如何简化依赖属性的生成和修改,但是该解决方案并不局限于依赖属性,比如下面的例子也可以使用该解决方案解决:
这个例子中CustomerId属性的生成,和依赖属性的生成同属一类问题,即需要输入许多内容,但是这些内容大部分都是重复的,只有一小部分内容是不一样的。这个属性的生成也可以通过Visual Studio和Resharper提供的功能实现,但是问题和依赖属性的问题是一样的,即不支持修改。使用该解决方案,也可以解决类似于这样的属性的生成。
需要说明的是,对于前述的各方法实施例,为了简单描述,故将其都表述为一系列的动作组合,但是本领域技术人员应该知悉,本发明并不受所描述的动作顺序的限制,因为依据本发明,某些步骤可以采用其他顺序或者同时进行。其次,本领域技术人员也应该知悉,说明书中所描述的实施例均属于优选实施例,所涉及的动作和模块 并不一定是本发明所必须的。
在上述实施例中,对各个实施例的描述都各有侧重,某个实施例中没有详述的部分,可以参见其他实施例的相关描述。
在本申请所提供的几个实施例中,应该理解到,所揭露的装置,可通过其它的方式实现。例如,以上所描述的装置实施例仅仅是示意性的,例如所述单元的划分,仅仅为一种逻辑功能划分,实际实现时可以有另外的划分方式,例如多个单元或组件可以结合或者可以集成到另一个系统,或一些特征可以忽略,或不执行。另一点,所显示或讨论的相互之间的耦合或直接耦合或通信连接可以是通过一些接口,装置或单元的间接耦合或通信连接,可以是电性或其它的形式。
所述作为分离部件说明的单元可以是或者也可以不是物理上分开的,作为单元显示的部件可以是或者也可以不是物理单元,即可以位于一个地方,或者也可以分布到多个网络单元上。可以根据实际的需要选择其中的部分或者全部单元来实现本实施例方案的目的。
另外,在本发明各个实施例中的各功能单元可以集成在一个处理单元中,也可以是各个单元单独物理存在,也可以两个或两个以上单元集成在一个单元中。上述集成的单元既可以采用硬件的形式实现,也可以采用软件功能单元的形式实现。
所述集成的单元如果以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个计算机可读取存储介质中。基于这样的理解,本发明的技术方案本质上或者说对现有技术做出贡献的部分或者该技术方案的全部或部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,包括若干指令用以使得一台计算机设备(可为个人计算机、移动终端、服务器或者网络设备等)执行本发明各个实施例所述方法的全部或部分步骤。而前述的存储介质包括:U盘、只读存储器(ROM,Read‐Only Memory)、随机存取存储器(RAM,Random Access Memory)、移动硬盘、磁碟或者光盘等各种可以存储程序代码的介质。
以上所述仅为本发明的优选实施例而已,并不用于限制本发明,对于本领域的技术人员来说,本发明可以有各种更改和变化。凡在本发明的精神和原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。