Suggestions for optimizing passing expressions as method parameters

北慕城南 提交于 2019-12-04 12:21:10

After thinking on the static caching of properties for a while I came up with this:

In this particular case all the property expressions I was interested in was on simple POCO DB entities. So I decided to make these classes partial and add the static cache properties in another partial pair class.

Having seen that this worked I decided to try and automate it. I looked at T4, but it didn't seem fit for this purpose. Instead I tried out https://github.com/daveaglick/Scripty, which is pretty awesome.

Here is the script I use to generate my caching classes:

using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Scripty.Core;
using System.Linq;
using System.Threading.Tasks;

bool IsInternalOrPublicSetter( AccessorDeclarationSyntax a )
{
    return a.Kind() == SyntaxKind.SetAccessorDeclaration &&
        a.Modifiers.Any( m => m.Kind() == SyntaxKind.PublicKeyword || m.Kind() == SyntaxKind.InternalKeyword );
}


foreach( var document in Context.Project.Analysis.Documents )
{
    // Get all partial classes that inherit from IIsUpdatable
    var allClasses = (await document.GetSyntaxRootAsync())
                    .DescendantNodes().OfType<ClassDeclarationSyntax>()
                    .Where( cls => cls.BaseList?.ChildNodes()?.SelectMany( _ => _.ChildNodes()?.OfType<IdentifierNameSyntax>() ).Select( id => id.Identifier.Text ).Contains( "IIsUpdatable" ) ?? false)
                    .Where( cls => cls.Modifiers.Any( m => m.ValueText == "partial" ))
                    .ToList();


    foreach( var cls in allClasses )
    {
        var curFile = $"{cls.Identifier}Exprs.cs";
        Output[curFile].WriteLine( $@"using System;
using System.Linq.Expressions;

namespace SomeNS
{{
    public partial class {cls.Identifier}
    {{" );
        // Get all properties with public or internal setter
        var props = cls.Members.OfType<PropertyDeclarationSyntax>().Where( prop => prop.AccessorList.Accessors.Any( IsInternalOrPublicSetter ) );
        foreach( var prop in props )
        {
            Output[curFile].WriteLine( $"        public static Expression<Func<{cls.Identifier},object>> {prop.Identifier}Expr = _ => _.{prop.Identifier};" );
        }

        Output[curFile].WriteLine( @"    }
}" );
    }

}

An input class could look like this:

public partial class SomeClass
{
    public string Foo { get; internal set; }
}

The script then generates a file named SomeClassExprs.cs, with the following content:

using System;
using System.Linq.Expressions;

namespace SomeNS
{
    public partial class SomeClassExprs
    {
        public static Expression<Func<SomeClass,object>> FooExpr = _ => _.Foo;
    }
}

The files are generated in a folder called codegen, which I exclude from source control.

Scripty makes sure to include the files during compilation.

All in all I'm very pleased with this approach.

:)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!