title: Simplify Attribute decorator on methods when referencing multiple libraries
body: <p>This is a minor inconvenience, but it ends up generating a lot of boiler plate code. I'm using multiple libraries (ServiceStack.Net, Json.Net, the DataContractSerializer, etc), and to coerce all possible interpreters to serialize/deserialize my objects correctly, I end up with lots of property definitions that look like this:</p>
  
  <pre><code>private const string select_comparisons = "select-comparisons";
  [DataMember(Name = select_comparisons, EmitDefaultValue = true)]
  [ApiMember(Name = select_comparisons)]
  [JsonProperty(select_comparisons, DefaultValueHandling = DefaultValueHandling.Populate, NullValueHandling = NullValueHandling.Include)]
  public bool SelectComparisons { get; set; }
  </code></pre>
  
  <p>Which is annoying. It would be preferable to compose something like this:</p>
  
  <pre><code>[MyAttributeToRuleThemAll("select-comparisons", EmitDefaultValue = true, IgnoreNulls = true)]
  public bool SelectComparisons { get; set; }
  </code></pre>
  
  <p>Where <code>MyAttributeToRuleThemAll</code> looks something like this:</p>
  
  <pre><code>public class MyAttributeToRuleThemAll : Attribute, DataMember, ApiMember, JsonProperty 
  {
      //insert attribute-specific logic in the constructor
  }
  </code></pre>
  
  <p>I realize the proposed solution isn't possible as you can't inherit in this way, but it seems like there should be some way to simplify common attributes into a single re-usable component.</p>
  
  <p>Update:</p>
  
  <p>I attempted to use <a href="https://stackoverflow.com/questions/38503146/combining-multiple-attributes-to-a-single-attribute">the answer from the referenced duplicate</a> using the following code.</p>
  
  <pre><code>[TypeDescriptionProvider(typeof(SerializableTypeDescriptionProvider))]
  public class SerializableTest
  {
      [Serializable("nu-id", DefaultValue = 2)]
      public int Id { get; set; }
  
      [Serializable("nu-key", DefaultValue = "2")]
      public string Key { get; set; }
  
  }
  
  public interface IMetadatAttribute
  {
      Attribute[] Process();
  }
  
  public enum DefaultValueOptions
  {
      Include,
      Exclude,
      IncludeAndPopulate
  }
  
  public class SerializableAttribute : Attribute, IMetadatAttribute
  {
      public DefaultValueHandling DefaultValueHandling { get; set; }
      public DefaultValueOptions DefaultValueOptions { get; set; }
      public bool EmitDefaultValue { get; set; }
      public bool IsRequired { get; set; }
      public bool ExcludeInSchema { get; set; }
      public bool AllowMultiple { get; set; }
      public string Name { get; set; }
      public string Description { get; set; }
      public string DataType { get; set; }
      public string Format { get; set; }
      public string ParameterType { get; set; }
      public string Route { get; set; }
      public string Verb { get; set; }
      public int Order { get; set; }
      public object DefaultValue { get; set; }
  
      public SerializableAttribute()
      {
          this.DefaultValueHandling = DefaultValueHandling.Include;
      }
  
      public SerializableAttribute(string name) : this()
      {
          Name = name;
      }
  
      public SerializableAttribute(string name, object defaultValue, bool emitDefaultValue, string description) : this(name)
      {
          DefaultValue = defaultValue;
          EmitDefaultValue = emitDefaultValue;
          Description = description;
      }
  
      public Attribute[] Process()
      {
          var attributes = new Attribute[]{
              new DataMemberAttribute() {
                  EmitDefaultValue = EmitDefaultValue,
                  IsRequired = IsRequired,
                  Name = Name,
                  Order = Order },
              new ApiMemberAttribute() {
                  Name = Name,
                  Description = Description,
                  ExcludeInSchema = ExcludeInSchema,
                  IsRequired = IsRequired,
                  AllowMultiple = AllowMultiple,
                  DataType = DataType,
                  Format = Format,
                  ParameterType = ParameterType,
                  Route = Route,
                  Verb = Verb
              },
              new JsonPropertyAttribute(Name) {
                  DefaultValueHandling = DefaultValueHandling,
                  PropertyName = Name,
                  NullValueHandling = NullValueHandling.Ignore,
                  ObjectCreationHandling = ObjectCreationHandling.Reuse
              },
              new DefaultValueAttribute(DefaultValue) {}
          };
          return attributes;
      }
  }
  
  public class SerializableDescriptor : PropertyDescriptor
  {
      PropertyDescriptor original;
      public SerializableDescriptor(PropertyDescriptor originalProperty)
          : base(originalProperty) =&gt; original = originalProperty;
      public override AttributeCollection Attributes
      {
          get
          {
              var attributes = base.Attributes.Cast&lt;Attribute&gt;();
              var result = new List&lt;Attribute&gt;();
              foreach (var item in attributes)
              {
                  if (item is IMetadatAttribute)
                  {
                      var attrs = ((IMetadatAttribute)item).Process();
                      if (attrs != null)
                      {
                          foreach (var a in attrs)
                              result.Add(a);
                      }
                  }
                  else
                      result.Add(item);
              }
              return new AttributeCollection(result.ToArray());
          }
      }
  
      public override Type ComponentType =&gt; original.ComponentType;
      public override bool IsReadOnly =&gt; original.IsReadOnly;
      public override Type PropertyType =&gt; original.PropertyType;
  
      public override bool CanResetValue(object component) =&gt; original.CanResetValue(component);
  
      public override object GetValue(object component)
      {
          return original.GetValue(component);
      }
      public override void ResetValue(object component) =&gt; original.ResetValue(component);
      public override void SetValue(object component, object value) =&gt; original.SetValue(component, value);
      public override bool ShouldSerializeValue(object component) =&gt; original.ShouldSerializeValue(component);
  }
  
  public class SerializableTypeDescriptor : CustomTypeDescriptor
  {
      ICustomTypeDescriptor original;
      public SerializableTypeDescriptor(ICustomTypeDescriptor originalDescriptor)
          : base(originalDescriptor) =&gt; original = originalDescriptor;
      public override PropertyDescriptorCollection GetProperties() =&gt; GetProperties(new Attribute[] { });
      public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
      {
          var properties = base.GetProperties(attributes).Cast&lt;PropertyDescriptor&gt;()
              .Select(p =&gt; new SerializableDescriptor(p))
              .ToArray();
          return new PropertyDescriptorCollection(properties);
      }
  }
  
  public class SerializableTypeDescriptionProvider : TypeDescriptionProvider
  {
      public SerializableTypeDescriptionProvider()
          : base(TypeDescriptor.GetProvider(typeof(object))) { }
  
      public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,
          object instance)
      {
          var baseDescriptor = base.GetTypeDescriptor(objectType, instance);
          return new SerializableTypeDescriptor(baseDescriptor);
      }
  }
  </code></pre>
  
  <p>Which you can run doing something like:</p>
  
  <pre><code>void Main()
  {
      var nuTest = new SerializableTest();
      var jsonOut = JsonConvert.SerializeObject(nuTest).Dump(); //or insert whatever ToJson/ToString logic here that you want
      //expecting: { "nu-id": 2, "nu-key": "2" }
      //getting: { "Id": 0, "Key": "null" }
  }
  </code></pre>
  
  <p>While this compiles and executes without error, the attributes specified are not returned as expected. Manually injecting the <code>[JsonProperty("nu-name")]</code> attribute works as expected. I'm assuming this Attribute approach is generated at compile time and not at runtime?  </p>