65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Genuilder.Extensibility 的强类型 AppSettings

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (5投票s)

2010 年 6 月 26 日

Ms-PL

2分钟阅读

viewsIcon

22012

downloadIcon

102

Genuilder.Extensibility 的实际用例:强类型 AppSettings。

目录

介绍

我上一篇关于 Genuilder.Extensibility 的文章 并不成功,我博客上的一个读者 告诉我,那是因为它没有展示任何实际用例。所以在这里!

目标是创建一个代码生成器,它允许您以类型安全的方式使用 AppSettings。我已经完成了关于此方面的文章,并将其集成到 Genuilder 中。问题在于,要理解我如何做到的,您必须理解 MSBuild 的工作原理。所以今天,我将向您展示如何使用 Genuilder.Extensibility 自己实现此功能。

安装

我将不再解释如何安装 Genuilder,因为它已在 CodePlex我的上一篇文章 中进行了充分描述。

创建插件

因此,让我们创建两个项目:第一个是一个包含配置文件和一些 appSettings 的控制台应用程序。第二个是我们的功能项目,一个类库。

不要忘记,功能项目的结尾必须是 .Gen

让我们在功能项目中创建插件 StronglyTypedAppSettingsPlugin

在此代码片段中,我订阅了 CodeRepositoryCodeItemCreated 事件。此事件针对项目中的每个源代码文件 + 配置文件触发。

然后,我在我的配置文件和名为 StronglyTypedSettings.cs 的目标文件之间创建一个依赖关系。

public class StronglyTypedAppSettingsPlugin : IPlugin
{
    #region IPlugin Members

    public void Initialize(ICodeRepository repository)
    {
        repository.CodeItemCreated += 
           new CodeItemCreatedHandler(repository_CodeItemCreated);
    }

    void repository_CodeItemCreated(ICodeRepository sender, CodeItem item)
    {
        if(item.Name.EndsWith(".config"))
        {
            var dependency = item.SourceOf("StronglyTypedSettings.cs");
            dependency.ShouldUpdateTarget += 
                new CodeDependencyHandler(dependency_ShouldUpdateTarget);
        }
    }

dependency_ShouldUpdateTarget 基于配置文件生成 StronglyTypedSettings.cs 中的代码。

void dependency_ShouldUpdateTarget(CodeDependency sender, CodeItem target)
{
    var configuration = 
        ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap()
    {
        ExeConfigFilename = ((FileCodeItem)sender.Source).File.FullName
    }, ConfigurationUserLevel.None);

    string generatedClass = "public static class AppConfigSettings{";

    foreach(KeyValueConfigurationElement setting in configuration.AppSettings.Settings)
    {

        string getter = "public static System.String " + setting.Key + 
          " { get{ return System.Configuration.ConfigurationManager.AppSettings[\"" + 
          setting.Key + "\"]; } }";
        generatedClass += getter;
    }
    generatedClass += "}";
    target.Content = generatedClass;

为了展示如何将警告和错误通知发送到构建,让我们在每次更新 StronglyTypedSettings.cs 时发送一个警告。

target.Logger.Send("Settings generated !!", 
              Genuilder.Extensibility.Utilities.LogType.Warning);
    }

    #endregion
}

这是控制台应用程序中的配置文件

<?xml version="1.0"?>
<configuration>
    <appSettings>
        <add key="SomeKey" value="SomeValue"/>
    </appSettings>
</configuration>

构建 ConsoleApplication1 并享受这个过程。

您甚至可以看到警告消息。

正如您所看到的,当您重新构建时,警告不会出现,因为源文件(App.config)没有更改。如果修改您的功能项目,则必须在构建之前清理项目。

此插件仅在 C# 中有效,如何让它在 VB.NET 中也有效?

我们只需修改 dependency_ShouldUpdateTarget 以使用 NRefactory 扩展。但在那之前,让我们在我们的项目中引用 NRefactory 集成程序集。

这是使用 CompilationUnitExtension(NRefactory 扩展)的 dependency_ShouldUpdateTarget 的代码... 稍微复杂一些,但可以在 C# 和 VB.NET 中使用!!

void dependency_ShouldUpdateTarget(CodeDependency sender, CodeItem target)
{
    var configuration = 
        ConfigurationManager.OpenMappedExeConfiguration(
        new ExeConfigurationFileMap()
    {
        ExeConfigFilename = ((FileCodeItem)sender.Source).File.FullName
    }, ConfigurationUserLevel.None);


    var targetNRefactoryExtension = 
      target.GetExtension<Genuilder.Extensibility.NRefactory.CompilationUnitExtension>();

    targetNRefactoryExtension.CompilationUnit.Children.Clear();
    var typeDeclaration = new TypeDeclaration(Modifiers.Public | Modifiers.Static, null)
    {
        Name = "AppConfigSettings"
    };
    targetNRefactoryExtension.CompilationUnit.Children.Add(typeDeclaration);



    foreach(KeyValueConfigurationElement setting in configuration.AppSettings.Settings)
    {

        var propertyDeclaration = new PropertyDeclaration(
               Modifiers.Public | Modifiers.Static, null, setting.Key, null)
        {
            TypeReference = new TypeReference(typeof(String).FullName)
        };
        var indexer = new IndexerExpression(
            new MemberReferenceExpression(
                new TypeReferenceExpression(
                    new TypeReference(typeof(ConfigurationManager).FullName)), "AppSettings")
                        , new List<Expression>()
                        {
                            new ICSharpCode.NRefactory.Ast.PrimitiveExpression(setting.Key)
                        });

        propertyDeclaration.GetRegion = new PropertyGetRegion(new BlockStatement(), null);
        propertyDeclaration.GetRegion.Block.Children.Add(new ReturnStatement(indexer));
        typeDeclaration.Children.Add(propertyDeclaration);

    }
    targetNRefactoryExtension.Save();
    target.Logger.Send("Settings generated !!", 
           Genuilder.Extensibility.Utilities.LogType.Warning);
}

结论

好吧,就这样。我很自豪我的文章简短且快速完成,这表明它们并不复杂!!

我非常有兴趣听取您关于新插件的想法。如果我受到激励,我很乐意实现它们!;)

© . All rights reserved.