using System; using System.CodeDom; using System.Collections.Generic; namespace CodeGenerator { public class AttributeBuilder { private CodeTypeDeclaration _attrDecl = new(); private List<(Type, string)> _fields = new(); private List<(Type, string, string)> _properties = new(); public AttributeBuilder() { _attrDecl.IsClass = true; _attrDecl.Attributes = MemberAttributes.Public; _attrDecl.BaseTypes.Add(typeof(Attribute)); } public AttributeBuilder(string name) : this() { _attrDecl.Name = name; } public AttributeBuilder New() { _attrDecl = new CodeTypeDeclaration(); _fields.Clear(); _properties.Clear(); return this; } public AttributeBuilder SetName(string name) { _attrDecl.Name = name; return this; } public AttributeBuilder SetAttributeUsage(CodeAttributeArgument usageArgs) { var attrUsage = new CodeAttributeDeclaration() { Name = nameof(AttributeUsageAttribute), Arguments = { usageArgs } }; _attrDecl.CustomAttributes.Add(attrUsage); return this; } // ReSharper disable always BitwiseOperatorOnEnumWithoutFlags public AttributeBuilder AddField(string name, MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) => AddField(typeof(T), name, attributes); public AttributeBuilder AddField(string type, string name, MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) => AddField(Type.GetType(type), name, attributes); public AttributeBuilder AddField(Type type, string name, MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) { var field = new CodeMemberField(type, name); field.Attributes = attributes; _attrDecl.Members.Add(field); _fields.Add((type, name)); return this; } public AttributeBuilder AddAutoProperty(Type type, string name, MemberAttributes attributes = MemberAttributes.Public, bool get = true, bool set = true) { AddField(type, $"_{name}", MemberAttributes.Private); return AddProperty(type, name, $"_{name}", attributes, get, set); } public AttributeBuilder AddProperty(Type type, string name, string backingPropertyName, MemberAttributes attributes = MemberAttributes.Public, bool get = true, bool set = true) { var prop = new CodeMemberProperty { Name = name, Type = new (type), Attributes = attributes, HasGet = get, HasSet = set }; if (get) { prop.GetStatements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), backingPropertyName))); } if (set) { prop.SetStatements.Add( new CodeAssignStatement( new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), backingPropertyName), new CodePropertySetValueReferenceExpression())); } _properties.Add((type, name, backingPropertyName)); _attrDecl.Members.Add(prop); return this; } public AttributeBuilder AddPropertiesConstructor() { var ctor = new CodeConstructor { Attributes = MemberAttributes.Public }; _attrDecl.Members.Add(ctor); _properties.ForEach(property => { ctor.Parameters.Add(new (property.Item1, property.Item2)); ctor.Statements.Add( new CodeAssignStatement( new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), property.Item3), new CodeVariableReferenceExpression(property.Item2))); }); return this; } public CodeTypeDeclaration Build() => _attrDecl; } }