Код: Выделить всё
[AutoSave]
public partial class GeneratedConfig : NotifiyingJsonSettings, IVersionable
{
[EnforcedVersion("1.0.0.0")]
public Version Version { get; set; } = new Version(1, 0, 0, 0);
public override string FileName { get; set; } = $"{AppContext.BaseDirectory}GeneratedConfig.json";
public virtual string TestString { get; set; }
public virtual bool TestBool { get; set; }
}
Код: Выделить всё
public partial class GeneratedConfig : NotifiyingJsonSettings, IVersionable
{
private System.Version version = new Version(1, 0, 0, 0);
[EnforcedVersion("1.0.0.0")]
public System.Version Version
{
get => version;
set
{
version = value;
OnPropertyChanged(nameof(Version));
Save();
}
}
private string fileName = $"{AppContext.BaseDirectory}NativeConfig.json";
public override string FileName
{
get => fileName;
set
{
if (fileName != value)
{
fileName = value;
OnPropertyChanged(nameof(FileName));
Save();
}
}
}
private string _testString;
public string TestString
{
get => _testString;
set
{
_testString = value;
OnPropertyChanged(nameof(TestString));
Save();
}
}
private bool _testBool;
public bool TestBool
{
get => _testBool;
set
{
_testBool = value;
OnPropertyChanged(nameof(TestBool));
Save();
}
}
}
Тип «GeneratedConfig» уже есть содержит определение для «Имя файла»
Тип «GeneratedConfig» уже содержит определение для «Версия»
Тип «GeneratedConfig» уже содержит определение для «TestBool»
Тип GeneratedConfig уже содержит определение для TestString
Я использую этот код генератора:
Код: Выделить всё
[Generator]
public class AutoSaveGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var classesWithAttribute = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (s, _) => s is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0,
transform: static (ctx, _) => GetClassWithAttribute(ctx))
.Where(static classWithAttribute => classWithAttribute is not null);
context.RegisterSourceOutput(classesWithAttribute, (context, classInfo) =>
{
var generatedCode = GenerateClassWithAutoSave(classInfo);
context.AddSource($"{classInfo!.ClassName}_AutoSave.g.cs", SourceText.From(generatedCode, Encoding.UTF8));
});
}
private static ClassInfo? GetClassWithAttribute(GeneratorSyntaxContext context)
{
var classDeclaration = (ClassDeclarationSyntax)context.Node;
var semanticModel = context.SemanticModel;
var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration) as INamedTypeSymbol;
if (classSymbol == null)
return null;
bool hasTargetAttribute = classSymbol.GetAttributes()
.Any(attr => attr.AttributeClass?.Name == "AutoSaveAttribute" ||
attr.AttributeClass?.ToDisplayString() == "AutoSave.AutoSaveAttribute");
if (!hasTargetAttribute)
return null;
var accessibility = classSymbol.DeclaredAccessibility.ToString().ToLower();
// Collect property information
var properties = classDeclaration.Members
.OfType
()
.Select(p => new PropertyInfo
{
Name = p.Identifier.Text,
Type = semanticModel.GetTypeInfo(p.Type).Type?.ToDisplayString() ?? "object",
IsVirtual = p.Modifiers.Any(SyntaxKind.VirtualKeyword),
IsOverride = p.Modifiers.Any(SyntaxKind.OverrideKeyword),
DefaultValue = p.Initializer?.Value.ToString(),
Attributes = p.AttributeLists
.SelectMany(a => a.Attributes)
.Select(a => a.ToString())
.ToList()
})
.ToList();
var baseTypes = GetBaseTypes(classSymbol);
// Return class info with properties and base types
return new ClassInfo
{
Accessibility = accessibility,
ClassName = classSymbol.Name,
Namespace = classSymbol.ContainingNamespace.ToDisplayString(),
Properties = properties,
BaseTypes = baseTypes
};
}
private static List GetBaseTypes(INamedTypeSymbol classSymbol)
{
var baseTypes = new List();
var currentBase = classSymbol.BaseType;
while (currentBase != null && currentBase.ToDisplayString() != "object")
{
baseTypes.Add(currentBase.ToDisplayString());
currentBase = currentBase.BaseType;
}
foreach (var iface in classSymbol.Interfaces)
{
baseTypes.Add(iface.ToDisplayString());
}
return baseTypes;
}
private static string GenerateClassWithAutoSave(ClassInfo classInfo)
{
var sb = new StringBuilder();
// Add required usings
sb.AppendLine("using Nucs.JsonSettings.Modulation;");
sb.AppendLine();
// File-scoped namespace
sb.AppendLine($"namespace {classInfo.Namespace};");
sb.AppendLine();
// Start class declaration with base types if any
var baseTypeList = classInfo.BaseTypes;
baseTypeList.Remove("Nucs.JsonSettings.JsonSettings");
baseTypeList.Remove("JsonSettings");
var baseTypesString = classInfo.BaseTypes.Count > 0 ? " : " + string.Join(", ", baseTypeList) : string.Empty;
sb.AppendLine($"{classInfo.Accessibility} partial class {classInfo.ClassName}{baseTypesString}");
sb.AppendLine("{");
foreach (var prop in classInfo.Properties)
{
string fieldName = char.ToLower(prop.Name[0]) + prop.Name.Substring(1);
// Generate private field with default value if it exists
sb.AppendLine($" private {prop.Type} {fieldName}" +
(prop.DefaultValue != null ? $" = {prop.DefaultValue};" : ";"));
// Add attributes if any
foreach (var attribute in prop.Attributes)
{
sb.AppendLine($" [{attribute}]");
}
// Generate property
sb.AppendLine($" {(prop.IsOverride ? "public override" : "public")}" +
$" {prop.Type} {prop.Name}");
sb.AppendLine(" {");
sb.AppendLine($" get => {fieldName};");
sb.AppendLine(" set");
sb.AppendLine(" {");
sb.AppendLine($" if ({fieldName} != value)"); // Add the condition here
sb.AppendLine(" {");
sb.AppendLine($" {fieldName} = value;");
sb.AppendLine($" OnPropertyChanged(nameof({prop.Name}));"); // Ensure OnPropertyChanged() is called
sb.AppendLine(" Save();"); // Call Save() only if value changed
sb.AppendLine(" }");
sb.AppendLine(" }");
sb.AppendLine(" }");
}
sb.AppendLine("}");
return sb.ToString();
}
private class ClassInfo
{
public string Accessibility { get; set; } = "public";
public string ClassName { get; set; }
public string Namespace { get; set; }
public List Properties { get; set; } = new();
public List BaseTypes { get; set; } = new();
}
private class PropertyInfo
{
public string Name { get; set; }
public string Type { get; set; }
public bool IsVirtual { get; set; }
public bool IsOverride { get; set; }
public string? DefaultValue { get; set; }
public List Attributes { get; set; } = new();
}
}
Подробнее здесь: https://stackoverflow.com/questions/791 ... -generator