How to add auto property using Codedom

264 Views Asked by At

I am trying to generate auto propery using codedom but with no luck. I tried different solutions and each one causing issue. I am trying to generate something like below

        [FindsBy(How = How.Id, Using = "AllTabs")]
        public IWebElement SaveButton { get; set; }

I was able to create attribute with no issue but unable to create auto property.

if I try to use the solution listed from here autoproperty i.e

        CodeTypeDeclaration newType = new CodeTypeDeclaration("TestType");
        CodeSnippetTypeMember snippet = new CodeSnippetTypeMember();

        snippet.Comments.Add(new CodeCommentStatement("this is integer property", true));
        snippet.Text="public int IntergerProperty { get; set; }";

        newType.Members.Add(snippet);

Then I am unable to add the attribute over the Property, it just prints out the property without the attribute. Is there any way to generate auto property and also use attributes?

2

There are 2 best solutions below

1
Ian Kemp On BEST ANSWER

Evidently you did not understand the answer you refer to. It is inserting literal text into the source stream, so the following should work for you:

        var newType = new CodeTypeDeclaration("TestType");
        var snippet = new CodeSnippetTypeMember();

        snippet.Text = @"
[FindsBy(How = How.Id, Using = ""AllTabs"")]
public IWebElement SaveButton { get; set; }
";

        newType.Members.Add(snippet);

Just be very aware that CodeSnippetTypeMember completely ignores the validation that CodeDom provides, so it's very easy to generate non-compiling code using this mechanism. Roslyn does support auto-properties natively when in a C# context.

As the accepted answer on the linked question states, the reason that CodeDom does not support auto-properties is that they are syntactic sugar that do not exist in all .NET languages, and CodeDom is intended to be as language-agnostic as possible. Therefore, CodeDom cannot know about or support the concept of an auto-property.

0
Christopher Hamkins On

To avoid using a snippet with its risk of errors uncaught until actually compiling, you can use a method to automatically create properties with a backing field (which is what the compiler internally does with an auto-property anyway):

private static CodeMemberProperty makeAutoProperty(CodeTypeDeclaration containingClass, CodeTypeReference propertyType, string propertyName )
        {
            CodeMemberField backingField = new CodeMemberField();
            backingField.Name = propertyName + "_";
            backingField.Type = propertyType;
            CodeVariableReferenceExpression backingFieldRef = new CodeVariableReferenceExpression(backingField.Name);
            containingClass.Members.Add(backingField);

            CodeMemberProperty property = new CodeMemberProperty();
            property.Name = propertyName;
            property.Type = propertyType;
            property.HasGet = true;
            property.HasSet = true;
            property.GetStatements.Add(new CodeMethodReturnStatement(backingFieldRef));
            property.SetStatements.Add(new CodeAssignStatement(backingFieldRef, new CodeVariableReferenceExpression("value")));
            containingClass.Members.Add(property);

            return property;
        }

This makes it just as easy to add as an autoproperty. You can use the method like this:

            // Make the property
            CodeMemberProperty saveButtonField = makeAutoProperty(_class, new CodeTypeReference("IWebElement"), "saveButton");
            // Modify the access
            saveButtonField.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            // Add the attribute decorator
            var attr = new CodeAttributeDeclaration(new CodeTypeReference("FindsBy"));
            saveButtonField.CustomAttributes.Add(attr);

This is the output:

        private IWebElement saveButton_;
        [FindsBy()]
        public IWebElement saveButton
        {
            get
            {
                return saveButton_;
            }
            set
            {
                saveButton_ = value;
            }
        }