简体   繁体   English

如何将CustomAttribute动态添加到所有对象属性?

[英]How can I add CustomAttribute to all object properties dynamically?

I have an object with multiple properties like this : 我有一个具有多个属性的对象,例如:

public int num1 { get; set; }

public int num2 { get; set; }

public string str1 { get; set; }

public string str2 { get; set; }

These properties are inside a class which is dynamically generated so it will erase all CustomAttributes on them. 这些属性位于动态生成的类中,因此它将擦除它们上的所有CustomAttributes。

I tried adding 我尝试添加

[Submit]
MyClass myObject

but it didn't spread on my object properties 但是它没有传播到我的对象属性上

Is there a way to do that dynamically inside the c# ? 有没有办法在c#中动态地执行此操作?

I'm having some trouble understanding your question, but let me attempt to clarify. 我在理解您的问题时遇到了一些麻烦,但让我尝试澄清一下。

I have an object with multiple attributes ... it will erase all CustomAttributes 我有一个具有多个属性的对象...它将清除所有CustomAttributes

In C# parlance, class members of the format <access> <type> <name> { get; set; } 用C#的说法,类成员的格式为<access> <type> <name> { get; set; } <access> <type> <name> { get; set; } <access> <type> <name> { get; set; } are referred to as "properties" rather than "attributes." <access> <type> <name> { get; set; }称为“属性”,而不是“属性”。 "Attributes," on the other hand, are the C# implementation of annotations, such as the custom attributes to which you are referring. 另一方面,“属性”是注释的C#实现,例如您要引用的自定义属性。

That said, I currently understand you to mean you have an automatically generated class with multiple properties. 就是说,我目前理解您是指您具有一个具有多个属性的自动生成的类。 You would like each of these properties to have their own custom attributes, but if you edit the class they are removed the next time it is generated, and you cannot get the class generator to include custom attributes. 您希望每个属性都具有自己的自定义属性,但是如果您编辑类,则在下次生成类时将其删除,并且无法使类生成器包含自定义属性。

It might be helpful to know more of the context of your class. 了解更多有关课程的内容可能会有所帮助。 How is it being generated, for example? 例如,它是如何生成的? If it is an Entity Framework class, the following SO question may provide some insight: Add data annotations to a class generated by entity framework . 如果是Entity Framework类,则以下SO问题可能会提供一些见解: 将数据注释添加到由Entity Framework生成的类 In general, is (or can you make) the generated class partial ? 通常,生成的类是否是(或可以使之) partial类? If so, then you can still follow the approach in the above question's answer, viz. 如果是这样,那么您仍然可以按照上述问题的答案中的方法进行操作 make your own partial class implementation that provides the properties' custom attributes. 制作自己的提供属性的自定义属性的局部类实现。

For example, if your generated class looks (or can be made to look) like this: 例如,如果您生成的类看起来(或可以使其看起来)像这样:

/// <auto-generated />
public partial class MyClass
{
    public int Num1 { get; set; }

    public int Num2 { get; set; }

    public string Str1 { get; set; }

    public string Str2 { get; set; }
}

You could write the other part of the partial class with the custom annotations, like this: 您可以使用自定义注释编写部分类的另一部分,如下所示:

/// human generated
public partial class MyClass
{
    [Submit]
    public int Num1 { get; set; }

    [Submit]
    public int Num2 { get; set; }

    [Submit]
    public string Str1 { get; set; }

    [Submit]
    public string Str2 { get; set; }
}

Again, without knowing more about your situation, I am not certain if this provides you the information you need, but I hope it at least gives you a starting point. 同样,在不了解您的情况的情况下,我不确定这是否可以为您提供所需的信息,但我希望至少可以为您提供一个起点。

Edit 编辑

If the class is not partial, you might consider wrapping your generated class with a class whose wrapping properties use the custom attribute. 如果该类不是局部类,则可以考虑使用其包装属性使用custom属性的类包装生成的类。 For example, 例如,

/// human generated
public class MyClassWrapper
{
    private readonly MyClass wrapped;

    public MyClassWrapper(MyClass wrapped)
    {
        this.wrapped = wrapped;
    }

    [Submit]
    public int Num1 { get => this.wrapped.Num1; set => this.wrapped.Num1 = value; }

    [Submit]
    public int Num2 { get => this.wrapped.Num2; set => this.wrapped.Num2 = value; }

    [Submit]
    public string Str1 { get => this.wrapped.Str1; set => this.wrapped.Str1 = value; }

    [Submit]
    public string Str2 { get => this.wrapped.Str2; set => this.wrapped.Str2 = value; }
}

Edit 2 编辑2

If you would rather have a more dynamic solution, at the cost of some design and runtime complexity, you might consider this SO question: How to add property-level Attribute to the TypeDescriptor at runtime? 如果您希望有一个更动态的解决方案,但要花一些设计和运行时复杂性,那么您可以考虑以下问题: 如何在运行时向TypeDescriptor添加属性级属性? . It seems to address a similar concern -- 似乎解决了类似的问题-

Really, it's for MS's Application Settings that generates code, so you can't extend it in any way property-wise. 确实,它是为MS的“应用程序设置”生成代码的,因此您无法以任何方式扩展它的属性。

I won't duplicate Gman's explanation entirely here, but essentially this approach consists of 我不会在这里完全重复Gman的解释,但是从本质上讲,这种方法包括

  1. Get the type ( MyClass ) or an instance of the type myObject 获取类型( MyClass )或类型myObject的实例
  2. Use TypeDescriptor.GetProvider(MyClass / myObject).GetTypeDescriptor(MyClass / myObject) to get the type or object's baseline ICustomTypeDescriptor 使用TypeDescriptor.GetProvider(MyClass / myObject).GetTypeDescriptor(MyClass / myObject)获取类型或对象的基线ICustomTypeDescriptor
  3. Construct his PropertyOverridingTypeDescriptor with this baseline descriptor 使用此基线描述符构造他的PropertyOverridingTypeDescriptor
  4. Iterate through MyClass / myObject 's properties' definitions with TypeDescriptor.GetProperties(MyClass / myObject) . 使用TypeDescriptor.GetProperties(MyClass / myObject)遍历MyClass / myObject的properties定义。 Use TypeDescriptor.CreateProperty to create a new property definition based on the current property's definition, that adds the custom attribute EditorAttribute (or in your case SubmitAttribute ), and use the PropertyOverridingTypeDescriptor constructed in 3. to use the new property definition. 使用TypeDescriptor.CreateProperty根据当前属性的定义创建一个新的属性定义,该属性定义将添加自定义属性EditorAttribute (或您的情况中的SubmitAttribute ),并使用在3.中构造的PropertyOverridingTypeDescriptor来使用新的属性定义。
  5. Construct his TypeDescriptorOverridingProvider with the PropertyOverridingTypeDescriptor constructed in 3. 使用3中构造的PropertyOverridingTypeDescriptor构造他的TypeDescriptorOverridingProvider
  6. Apply the new property definitions to MyClass / myObject with TypeDescriptor.AddProvider 使用TypeDescriptor.AddProvider将新的属性定义应用于MyClass / myObject

One more way to add attributes to a dynamically generated class is to add one more command line app to your code generation pipeline. 将属性添加到动态生成的类的另一种方法是在代码生成管道中添加一个命令行应用程序。

Here's an example how to rewrite C# code file with Microsoft.CodeAnalysis.CSharp library: 这是一个如何使用Microsoft.CodeAnalysis.CSharp库重写C#代码文件的示例:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System;
using System.IO;

namespace SB.Common.ContractGenerator
{
    class SubmitAttributeAdder : CSharpSyntaxRewriter
    {
       public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)=>
            node.WithAttributeLists(
                node.AttributeLists.Count == 0
                    ? node.AttributeLists.Add(SyntaxFactory.AttributeList()
                         .AddAttributes(SyntaxFactory.Attribute(
                            SyntaxFactory.ParseName("Submit")))
                        // Add some whitespace to keep the code neat.
                        .WithLeadingTrivia(node.GetLeadingTrivia())
                        .WithTrailingTrivia(SyntaxFactory.Whitespace(Environment.NewLine)))
                    : node.AttributeLists);
    }

    class Program
    {
        static void Main(string[] args)
        {
            // The file name to be injected as a command line parameter
            var tree = CSharpSyntaxTree.ParseText(
                SourceText.From(File.ReadAllText("Test.cs")));

            File.WriteAllText("Test.cs",
                new SubmitAttributeAdder().Visit(tree.GetRoot()).ToString());
        }
    }
}

First, the input C# code file is parsed as the syntax tree, and then the SubmitAttributeAdder class skims through all declared classes and their properties to amend an attribute list for each of them. 首先,将输入的C#代码文件解析为语法树,然后SubmitAttributeAdder类浏览所有已声明的类及其属性,以修改每个属性的属性列表。

After that the modified syntax tree is saved back to the same file. 之后,修改后的语法树将保存回同一文件。

Here the app only adds the Submit attribute in case the attribute list of a property is empty, but one can easily make the logic more sophisticated - eg check whether there are other attributes, add corresponding using <namespace> for the Submit attribute and so on. 在这里,该应用仅在属性的属性列表为空的情况下添加Submit属性,但是可以轻松使逻辑更复杂-例如,检查是否还有其他属性, using <namespace>添加相应的Submit属性,等等。 。

An example Test.cs file before running the app: 运行应用程序之前的示例Test.cs文件:

namespace MyProject
{
    class MyClass
    {
        public int num1 { get; set; }

        public int num2 { get; set; }

        public string str1 { get; set; }

        public string str2 { get; set; }
    }
}

...and after: ...之后:

namespace MyProject
{
    class MyClass
    {
        [Submit]
        public int num1 { get; set; }

        [Submit]

        public int num2 { get; set; }

        [Submit]

        public string str1 { get; set; }

        [Submit]

        public string str2 { get; set; }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM