Is it possible to extend an attribute? - c#

In an app, I use different frameworks/technologies to serialize/deserialize objects. To ignore properties in the objects there are attributes like BsonIgnore or JsonIgnore.
[JsonIgnore]
[BsonIgnore]
public bool MyProperty
{
get;
set;
}
How can I create an attribute that extends from BsonIgnore and JsonIgnore so that I only need to specify one attribute for MyProperty?
The following does not work as an attribute has to extend System.Attribute.
[AttributeUsage(AttributeTargets.Class)]
public class MyIgnoreAttribute : BsonIgnore, JsonIgnore
{ ... }
-------------------------
[MyIgnore]
public bool MyProperty
{
get;
set;
}

C# doesn't support multiple-inheritance, and each of those types is sealed, so they couldn't be inherited from anyway. But there may be a different approach to do what you're trying to do.
If it is a predictable thing, for example: if something which has one attribute should always have the other attribute; you could use Aspect-Oriented Programming to inject the other attribute at compile time.
Your next question is going to be "how do I do that?", the answer to which will depend on what product you use.
Your question after that will be "which product should I use to do AOP?", which is off-topic, as shown here (hint: take a look at the linked page).

It's useless and impossible.
Look at source code of JsonIgnoreAttribute:
namespace Newtonsoft.Json
{
/// <summary>
/// Instructs the <see cref="T:Newtonsoft.Json.JsonSerializer" /> not to serialize the public field or public read/write property value.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public sealed class JsonIgnoreAttribute : Attribute
{
}
}
As you see, it does nothing.
In newtonsoft framework there is a code, that check that property has JsonIgnoreAttribute and do special work for that. It expects JsonIgnoreAttribute only.
Also, JsonIgnoreAttribute is sealed, you can't extend it.

Related

DataContract secret behavior?

Every time I meet this attribute, I always see such usage:
[DataContract]
class DataTransferObject
{
[DataMember]
public int Value {get;set;}
}
And in this example all inherited members should apply DataMember attribute to every property or field, this can lead to VERY clumsy and poilerplate code. But, recently I found (maybe secret feature?) a very elegant way of using it:
[DataContract]
public abstract class DTOBase
{
}
public class MyDTO : DTOBase
{
public int Value {get;set;}
public MyDTO(){} //important part is here
}
Important part: You should always explicitly define parameterless constructor, otherwise it won't serialize properly.
And yeah. It will serialize all its public members, no matter how deep will be inheritance, without need to apply attributes to members or class definitions.
Is this somehow documented somewhere (I didn't found)? Because, I were very supprized how much of boilerplate can be avoided.
Actually, you don't need to use DataContract and DataMember attributes if you don't want to, however they give you flexibility in defining what needs to be serialized and how.
I suggest starting with article Serializable Types on MSDN, it has a lot of information how Data Contract serializer works. Here are first 2 paragraphs, proving that you don't need to use attributes:
By default, the DataContractSerializer serializes all publicly visible
types.
All public read/write properties and fields of the type are
serialized. You can change the default behavior by applying the
DataContractAttribute and DataMemberAttribute attributes to the types
and members This feature can be useful in situations in which you have
types that are not under your control and cannot be modified to add
attributes. The DataContractSerializer recognizes such "unmarked"
types.
The main rules that apply to your case are:
DataContract attribute is not inherited. You can either apply it or not on your base class DTOBase, it is ignored in child class MyDTO. You can remove DataContract attribute from DTOBase class and result will be the same.
If you use DataContract attribute on a class, then only members that have DataMember attribute will be serialized. This is what happened in class DataTransferObject in your first sample.
If you do not use DataContract attribute on a class, then all public members of a class are serialized. This is what happened with your class MyDTO.

Why is the C# SerializedAttribute is sealed?

I was trying to create an attribute that implies [Serializable] but I noticed that this SerializableAttribute class is sealed.
In Java it was possible to create an interface (say, MyInterface) that is inherited from Serializable interface and so all the subclasses of MyInterface would also be serializable, even its sub-sub classes would be so.
Let's say I am creating an ORM and I want customers to annotate their entity classes as [DatabaseEntity] but in order to make sure that entities are serializable, I also need to ask them to attribute their classes with extra [Serializable] which does not look quite compact and neat.
I am wondering why SerializableAttribute class is sealed and why has Inherited=false which implies that subclasses of serializable class will not be serializable unless it is explicitly stated. What motives are behind these design choices?
The SerializableAttribute is only used by the BinaryFormatter. If you are writing your own serialiser then don't worry about.
The sealed keyword is applied to the attribute not the class associated with the attribute. It is saying that the SerializableAttribute cannot be subclassed.
The BinaryFormatter uses an opt-in model. Any class (or subclass) must specify that it is serializable. This why the Inherited=false is used.
It's suggested best practice that all .Net attributes should be sealed, according to Microsoft:
The .NET Framework class library provides methods for retrieving custom attributes. By default, these methods search the attribute inheritance hierarchy; for example System.Attribute.GetCustomAttribute searches for the specified attribute type, or any attribute type that extends the specified attribute type. Sealing the attribute eliminates the search through the inheritance hierarchy, and can improve performance. [my emphasis]
So [Serializable] is sealed because it's quicker for .Net reflection to check the attributes. The cost is that you can't inherit and extend SerializableAttribute.
You can make your own un-sealed attributes if you want (you'll get code analysis warnings though).
This gets a little confusing with how attributes are used in inheritance for the classes that they apply to. It's probably best to use an example:
[Serializable]
public class A
{
public int SimpleSerialisableProperty { get; set;}
}
public class B : A
{
public C ComplexReferenceProperty { get; set; }
}
[Serializable]
public class D : A
{
public bool AnotherSerialisableProperty { get; set;}
}
You asked why SerializableAttribute.Inherited = false and this is why:
Class A is marked as [Serializable], and it is.
However class B inherits A and extends it with properties that are not serialisable. If .Net tries to serialise B it will encounter an error.
That Inherited = false tells .Net that just because A has been marked as [Serializable] not every class that inherits it will be serialisable too.
Now class D inherits A and is serialisable, so it gets its own [Serializable] attribute.
Finally, in terms of design attributes are a great way of extending behaviour (nice UI editors in property grids, etc). However they are terrible at enforcing it. If you need your customers to implement their entity classes in a particular way then an abstract base class or an interface is a much better way to go. If you make it an attribute then you're basically letting them know that [Serializable] is an option that you can handle either way.
Serialization is not a magic thing and you don't need any attribute to serialize an object. It is a process of writing your class' properties and fields to a stream (and attributes are only directives to serializers about how to behave while outputting an object).
See this over-simplified serializer code which totally ignores all attributes including NonSerializable
object obj = yourObject;
var props = obj.GetType()
.GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(obj, null));
string serializedText = String.Join("\n",
props.Select(kv => kv.Key + "=" + kv.Value ?? kv.Value.ToString()));
Above code, for example, would give
IsEmpty=False
X=3
Y=5
for object obj = new Point(3,5);
Deserialization process would be to read these values and set the properties back accordingly.
Put the [Serializable] attribute on top of the class you want serialized. Serialization is opt-in process. You have to manually do that for each class you want serialized. There are bunch of other keywords.

Why is .Net best practice to design custom attributes as sealed?

I'm reading Pro C# 2010 and the .Net 4 Platform by Andrew Troelsen.
In Chapter 15 about Attributes exists a note:
Note: For security reasons, it is considered a .Net best practice to design all custom attributes as sealed.
The author doesn't explain why, can someone explain why?
CA1813: Avoid unsealed attributes:
The .NET Framework class library provides methods for retrieving
custom attributes. By default, these methods search the attribute
inheritance hierarchy; for example Attribute.GetCustomAttribute
searches for the specified attribute type, or any attribute type that
extends the specified attribute type. Sealing the attribute eliminates
the search through the inheritance hierarchy, and can improve
performance.
Ref: https://learn.microsoft.com/visualstudio/code-quality/ca1813-avoid-unsealed-attributes
Attributes are simply metadata discovered at runtime. As it is quoted, if someone else derives from your custom attribute class, by default .NET will find them too, which may imply a security risk if the derived attribute class is modifying the behavior of your original attribute in a way to you never intended to.
Even though performance is the prime reason to seal attribute classes, here is a formidable article dealing with its security side.
There is one more reason to seal attributes.
Consider the following attribute:
[AttributeUsageAttribute(AttributeTargets.Class, AllowMultiple = false)]
public class Attr1 : Attribute
{
}
Here you allow only single attribute decoration: AllowMultiple = false
Compiler won't allow this:
[Attr1]
[Attr1]
public class Foo
{
}
Later in your code you can safely call memberInfo.GetCustomAttribute() which will throw AmbiguousMatchException if more then one attribute of the given type was found.
Let's now inherit:
public class Attr2 : Attr1
{
}
Now compiler is silent.
[Attr1]
[Attr2]
public class Foo
{
}
So if later somebody inherits from your attribute and passes back to your code some entity marked with both attributes unexpected exception will be thrown.
Full example:
class Program
{
static void Main(params string[] args)
{
typeof(Foo).GetCustomAttribute<Attr1>();
}
[AttributeUsageAttribute(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class Attr1 : Attribute
{
}
public class Attr2 : Attr1
{
}
[Attr1]
[Attr2]
public class Foo
{
}
[Attr1]
public class Bar : Foo
{
}
}
Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries just says:
DO seal custom attribute classes, if possible. This makes the look-up for the attribute faster.
I didn't see anything about security in that section, but #Teoman Soygul makes a good point. So I'd agree with Mr. Troelsen.

Fields vs. Properties and XMLSerializers (101)

So I've been studying the use of various Serializers in the .NET Framework and while trying to experiment on preventing certain objects in a class from being serialized I was thrusted back to some very basic programming questions that I "thought" I knew. Given this example:
public class Example
{
public string examName;
[XmlIgnore]
public int exampleNumber;
public Example()
{ }
[XmlIgnore]
public int ExampleNumberTwo { get; set; }
}
I can create an instance of this class and using the XMLSerializer can output the content of this class in XML format. The [XmlIgnore] attribute actually does what I'd expected; it prevents the serialization of the referenced items.
So venturing further I replaced the [XmlIgnore] declaration for "exampleNumber" with [NonSerializable] expecting the similar results but the output did not change. After searching through resources, it was stated that the [NonSerializable] attribute should only be used on fields and [XmlIgnore] attributes should be used on properties.
Yet another post stated that the [NonSerializable] attribute has no effect when using the XMLSerializer but will produce the expected results when using the SOAP or BinaryFormatter. So I'm lost on the concept at this point.
But this brought me to the basic question, what defines a field vs. a property? I know its a basic question and I've even viewed other discussions here but the degree of clarity I am looking for still wasn't really clear.
I can use the [XmlIgnore] attribute on the property (ExampleNumberTwo) or the variable (exampleNumber) so the statement that it can ONLY be used on Properties doesn't seem correct.
But then again, I have always referred to the objects in my example such as (examName) and (exampleNumber) as being member variables. So what exactly is the signature of a "Field"
Can anyone shed some light on this?
The MSDN documentation supports the idea that [NonSerialized] only gives the expected results with the binary and SOAP serializers:
When using the BinaryFormatter or SoapFormatter classes to serialize
an object, use the NonSerializedAttribute attribute to prevent a field
from being serialized. For example, you can use this attribute to
prevent the serialization of sensitive data.
The target objects for the NonSerializedAttribute attribute are public
and private fields of a serializable class. By default, classes are
not serializable unless they are marked with SerializableAttribute.
During the serialization process all the public and private fields of
a class are serialized by default. Fields marked with
NonSerializedAttribute are excluded during serialization. If you are
using the XmlSerializer class to serialize an object, use the
XmlIgnoreAttribute class to get the same functionality. Alternatively,
implement the ISerializable interface to explicitly control the
serialization process. Note that classes that implement ISerializable
must still be marked with SerializableAttribute.
In terms of "field" vs. "property", fields are straight data variables contained by a class. Properties are actually specially named methods on the class (get_PropName() and set_PropName()). In your code, the compiler allows you to use properties the same way you would use a field, and then inserts the appropriate get/set call for you.
Oftentimes, properties will be simple wrappers around a field:
private int myField;
public int MyProperty
{
get { return myField; }
set { myField = value; }
}
But they don't have to be:
public int TodaysDate
{
get { return DateTime.Today; }
}
In general, you want all your fields to be private, since they're supposed to be implementation details. Any simple data that you'd like to expose should be done via a property, since you can easily surround the data access with (changeable) logic.
In C#, the short answer is that properties have get and/or set methods, while fields do not. VB.NET makes it a little more evident by requiring the "Property" qualifier to be used to differentiate one.
With C#, you can just append " { get; set; }" to the end of a field's definition and it's now a property.
Where this really comes into play is in reflection. Fields and Properties are segregated from one another into different enumerable collections.
This answer to What are the differences between the XmlSerializer and BinaryFormatter will help you get started in the right direction.

get an attributes class

Is it possible in C# in an attribute constructor to get the class that has the attribute assigned to it without having to pass that class name in.
[MyAttr]
public class A{}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
[Serializable]
public class MyAttrAttribute: Attribute
{
public MyAttrAttribute()
{
//get info here about the class A etc
}
}
Attribute instances are completely independent of the types/fields/properties that they decorate; there is absolutely no way of accessing the context from an attribute. However, attributes also aren't created until you explicitly query them with reflection.
If you want to invoke some logic, then it must be done explicitly through code - so you might consider adding a method on your attribute that accepts the context object:
public void Invoke(object instance) {...}
for example, then use GetCustomAttribute to obtain it, cast it, and call .Invoke()
No. But why would you want to do this? What are you trying to achieve?
When you retrieve an attribute at run time, you do so from the type object representing the class. So even though the information is not stored in the attribute object, it is readily available.
This would have been a convenient feature, nice question. But fundamentally attributes are meant only as meta data to inspectors not to be inspectors - they are constant data.

Categories

Resources