Pohon ekspresi System.Linq.Expressions
memungkinkan untuk mengekspresikan maksud tidak hanya dengan kode itu sendiri, tetapi juga oleh struktur dan sintaksnya.
Kreasi mereka dari ekspresi lambda sebenarnya adalah gula sintaksis, di mana kode biasa ditulis, dan kompilator membangun pohon sintaksis ( AST ) darinya , yang menyertakan referensi ke objek dalam memori, dan menangkap variabel. Hal ini memungkinkan Anda untuk memanipulasi tidak hanya data, tetapi juga kode dalam konteks penggunaannya: menulis ulang, menambah, mentransfer, dan hanya kemudian mengompilasi dan mengeksekusi.
Kompilasi run-time menghasilkan delegasi produktif yang seringkali lebih cepat daripada yang dikompilasi pada waktu pembuatan ( dengan biaya overhead yang lebih sedikit ). Namun, kompilasi itu sendiri membutuhkan waktu hingga puluhan ribu kali lebih lama daripada memanggil hasil kompilasi.
(patokan)
Bertindak |
Waktu, ns |
|---|---|
Memanggil Kompilasi Cache |
0,5895 ± 0,0132 ns |
Kompilasi dan Panggil |
83.292.3139 ± 922.4315 ns |
Hal ini sangat menyinggung ketika ekspresi sederhana, misalnya, hanya berisi akses ke properti (di perpustakaan untuk pemetaan, serialisasi, pengikatan data), panggilan ke konstruktor atau metode (untuk solusi IoC / DI).
Delegasi yang dikompilasi biasanya di-cache untuk digunakan kembali, tetapi ini tidak disimpan dalam skrip ketika akses pertama terjadi pada banyak waktu. Dalam kasus seperti itu, run-time dari ekspresi kompilasi menjadi signifikan dan menunda peluncuran aplikasi atau jendela individu.
Untuk mengurangi waktu yang dibutuhkan untuk mendapatkan delegasi dari pohon ekspresi, gunakan:
Interpretasi bawaan.
Kebutuhan untuk menggunakan interpreter sebagai ganti compiler ditunjukkan oleh flag yang sesuai:
Expression.Compile(preferInterpretation: true)
Itu terjadi melalui refleksi, tetapi dengan overhead membentuk tumpukan instruksi.
Xamarin.iOS, Xamarin.watchOS, Xamarin.tvOS, Mono.PS4 Mono.XBox IL (
System.Reflection.Emit
) .
FastExpressionCompile @dadhi.
p IL .
JIT Mono Interpreter.
.
, .
, . , Fasterflect,
System.Reflection.Emit
Mono Interpreter.
, , :
- (design-time) (compile-time).
compile-time .
API , . , , . - DI — , .
API , . : , run-time compile-time — . , — .
,
namespace Namespace
{
public class TestClass
{
public int Property { get; set; }
}
}
System.Linq.Expressions.Expression<T>
Expression<Func<TestClass, int>> expression = o => o.Property;
Func<object, object> _ = obj => ((Namespace.TestClass)obj).Property;
Action<object, object> _ => (t, m) => ((Namespace.TestClass)t).Property
= (System.Int32)m;
:
namespace ExpressionDelegates.AccessorRegistration
{
public static class ModuleInitializer
{
public static void Initialize()
{
ExpressionDelegates.Accessors.Add("Namespace.TestClass.Property",
getter: obj => ((Namespace.TestClass)obj).Property,
setter: (t, m) => ((Namespace.TestClass)t).Property = (System.Int32)m);
}
}
}
, , :
, Roslyn Source Generators C# .
, Roslyn Source Generators , . . Roslyn API, code-fix.
Roslyn Source Generators - ( !) .
:
namespace Microsoft.CodeAnalysis
{
public interface ISourceGenerator
{
void Initialize(GeneratorInitializationContext context);
void Execute(GeneratorExecutionContext context);
}
}
.
Initialize
- . GeneratorInitializationContext
.
Execute
, , , , .
Roslyn SyntaxTree
:
GeneratorExecutionContext.Compilation.SyntaxTrees
:
semanticModel = GeneratorExecutionContext.Compilation.GetSemanticModel(SyntaxTree)
, ( ) , , .
- System.Linq.Expressions.Expression<T>
- , , :
, (Symbol
), :
, ;
;
IsStatic
,IsConst
,IsReadOnly
.
.
Roslyn API (Microsoft.CodeAnalysis
) , c API (System.Reflection
). ISymbol.ToDisplayString(SymbolDisplayFormat)
c :
/, :
:
var sourceBuilder = new StringBuilder(
@"namespace ExpressionDelegates.AccessorRegistration
{
public static class ModuleInitializer
{
public static void Initialize()
{");
foreach (var line in registrationLines)
{
sourceBuilder.AppendLine();
sourceBuilder.Append(' ', 6).Append(line);
}
sourceBuilder.Append(@"
}
}
}");
GeneratorExecutionContext.AddSource(
"AccessorRegistration",
SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
... :)
, Source Generators , C# 9+. .NET 5.
Roslyn Source Generators API .NET Standard, .NET Core, .NET Framework Xamarin Uno.SourceGeneration.
Uno.SourceGeneration ISourceGenerator [Generator], # 9 Microsoft.CodeAnalysis
Uno:
using Uno.SourceGeneration;
using GeneratorAttribute = Uno.SourceGeneration.GeneratorAttribute;
using ISourceGenerator = Uno.SourceGeneration.ISourceGenerator;
.
API , , .
Module Initializer. ( ), . CLR, , C# c [ModuleInitializer]
9 .
Fody — Fody.ModuleInit
. ModuleInitializer
. .
Fody.ModuleInit
MSBuild FodyWeavers.xml
Weaver- Fody .
, :
Source Generator , ,
ModuleInitializer
.
Fody.ModuleInit
ModuleInitializer
.
ModuleInitializer
, .
:
Expression<Func<string, int>> expression = s => s.Length;
MemberInfo accessorInfo = ((MemberExpression)expression.Body).Member;
Accessor lengthAccessor = ExpressionDelegates.Accessors.Find(accessorInfo);
var length = lengthAccessor.Get("17 letters string");
// length == 17
, :
, - .
|
|
, |
|---|---|
|
4.6937 ± 0.0443 |
|
5.8940 ± 0.0459 |
|
191.1785 ± 2.0766 |
|
88,701.7674 ± 962.4325 |
|
|
|
|
1.7740 ± 0.0291 |
|
5.8792 ± 0.1525 |
|
163.2990 ± 1.4388 |
|
88,103.7519 ± 235.3721 |
|
|
|
|
1.1767 ± 0.0289 |
|
4.1000 ± 0.0185 |
|
186.4856 ± 2.5224 |
|
83,292.3139 ± 922.4315 |
, — , .
System.Reflection.MemberInfo
. .
.
: github/ExpressionDelegates, nuget.
, Source Generators :
Source Generator Playground (github).
Roslyn Source Generators , .
Visual Studio.
Roslyn Syntax API .
Source Generator . .
Visual Studio «Just-In-Time debugger»Tools -> Options -> Debugging -> Just-In-Time Debugging -> ☑ Managed
.
*.cs
, Visual Studio 16.8.
Uno.SourceGeneration :\obj\{configuration}\{platform}\g\
.
Roslyn Source Generators MSBuildEmitCompilerGeneratedFiles
.
:\obj\{configuration}\{platform}\generated\
,CompilerGeneratedFilesOutputPath
.
Source Generators MSBuild.
Uno.SourceGeneration
GeneratorExecutionContext.GetMSBuildPropertyValue(string)
Untuk Roslyn Source Generators, properti yang diperlukan harus terlebih dahulu ditetapkan secara terpisah di grup MSBuild
CompilerVisibleProperty
dan baru kemudian dipanggil:
GeneratorExecutionContext.AnalyzerConfigOptions.GlobalOptions .TryGetValue("build_property.<PROPERTY_NAME>", out var propertyValue)
Dari generator, Anda dapat melempar peringatan dan membuat kesalahan.
//Roslyn Source Generators GeneratorExecutionContext.ReportDiagnostic(Diagnostic) //Uno.SourceGeneration: GeneratorExecutionContext.GetLogger().Warn/Error().