AusdrucksbÀume System.Linq.Expressions
ermöglichen es, Absichten nicht nur durch den Code selbst, sondern auch durch seine Struktur und Syntax auszudrĂŒcken.
Ihre Erstellung aus Lambda-AusdrĂŒcken ist in der Tat syntaktischer Zucker, in den gewöhnlicher Code geschrieben wird, und der Compiler erstellt daraus einen Syntaxbaum ( AST ), der Verweise auf Objekte im Speicher enthĂ€lt, und erfasst Variablen. Auf diese Weise können Sie nicht nur Daten, sondern auch den Code, in dessen Kontext sie verwendet werden, bearbeiten: neu schreiben, ergĂ€nzen, ĂŒbertragen und erst dann kompilieren und ausfĂŒhren.
Durch die Laufzeitkompilierung werden Leistungsdelegierte erstellt, die hÀufig schneller sind als die zum Zeitpunkt der Erstellung kompilierten ( auf Kosten eines geringeren Overheads ). Die Kompilierung selbst dauert jedoch bis zu Zehntausenden Mal lÀnger als das Aufrufen des Kompilierungsergebnisses.
(Benchmark)
Handlung |
Zeit, ns |
|---|---|
Cached Compile Invoke |
0,5895 ± 0,0132 ns |
Kompilieren und aufrufen |
83.292,3139 ± 922,4315 ns |
Dies ist besonders anstöĂig, wenn der Ausdruck einfach ist, z. B. nur Zugriff auf eine Eigenschaft (in Bibliotheken fĂŒr Zuordnung, Serialisierung, Datenbindung) enthĂ€lt, die einen Konstruktor oder eine Methode aufruft (fĂŒr IoC / DI-Lösungen).
Kompilierte Delegaten werden normalerweise zwischengespeichert, um wiederverwendet zu werden. Dies wird jedoch nicht in Skripten gespeichert, wenn der erste Zugriff hĂ€ufig gleichzeitig erfolgt. In solchen FĂ€llen wird die Laufzeit des Kompilierens von AusdrĂŒcken erheblich und verzögert den Start der Anwendung oder einzelner Fenster.
Verwenden Sie Folgendes, um die Zeit zu verkĂŒrzen, die zum Abrufen von Delegaten aus AusdrucksbĂ€umen erforderlich ist:
Eingebaute Interpretation.
Die Notwendigkeit, einen Interpreter anstelle eines Compilers zu verwenden, wird durch das entsprechende Flag angezeigt:
Expression.Compile(preferInterpretation: true)
Dies geschieht durch Reflexion, jedoch mit dem Aufwand, einen Befehlsstapel zu bilden.
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)
FĂŒr Roslyn Source Generators mĂŒssen die erforderlichen Eigenschaften zuerst in der MSBuild-Gruppe separat festgelegt
CompilerVisibleProperty
und erst dann aufgerufen werden:
GeneratorExecutionContext.AnalyzerConfigOptions.GlobalOptions .TryGetValue("build_property.<PROPERTY_NAME>", out var propertyValue)
Vom Generator aus können Sie Warnungen auslösen und Fehler erstellen.
//Roslyn Source Generators GeneratorExecutionContext.ReportDiagnostic(Diagnostic) //Uno.SourceGeneration: GeneratorExecutionContext.GetLogger().Warn/Error().