In order to decorate a class with AttributeUsage, the decorated class must also inherit from Attribute.
Can I enforce a similar constraint with a custom attribute?
The AttributeUsageAttribute is apparently a core feature of the language, so this restriction is mandated by the C# specification:
A class that is decorated with the AttributeUsage attribute must derive from System.Attribute, either directly or indirectly. Otherwise, a compile-time error occurs.
That means there's no straightforward way of achieving such a restriction. You can write a custom static analyzer to throw warnings at erroneous usage, or see Anton Anpilogov's answer for a workaround.
The only way to do that is to use protected attribute, but in that case, you'll force users of your attribute to inherit from your attribute class.
abstract class CustomAttribute : Attribute {
[AttributeUsage(AttributeTargets.Class)]
protected sealed class MyTestAttribute : Attribute {}
}
[MyTest]
class DerivedFromYourCustomAttribute : CustomAttribute {
}
[MyTest]
class NotDerivedFromYourCustomAttribute {
}
Related
I'm trying to create a custom C# Validation Attribute(without sealed keyword) for Data Annotation.
public class MyValidatorAttribute : ValidationAttribute
{
}
But Microsoft page here says "Make the class not inheritable." why?
Do I overlooked something by allowing "MyValidatorAttribute" class as inheritable?
According to this code analysis rule it is for performance reasons.
When retrieving custom attributes .NET will normally search the inheritance hierarchy and this can add an overhead that may not be required.
This would not stop you creating an abstract attribute that several sealed implementations inherited from.
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.
I recently read about attributes and reflection and I thought it would be a good method to include metadata in my program. I have this abstract class and I wanted all classes inheriting from it to declare with the class some attribute, since I wanted custom components(those derived classes) to be created for my program and wanted to read the metadata of these classes on runtime. However, the derived classes all have to explicitly declare the attribute in which I store metadata. So how to I force an attribute declaration in the derived classes? Thanks.
Define your attribute class to itself have an AttributeUsageAttribute attribute where the Inherited property is true.
Or don't, since that's the default...
Derived targets (that is, classes if the attribute is on a class, methods if it is on a method, etc.) will then inherit the attribute without explicit declaration.
If by "force", you mean "compile time enforcement": You can't.
As Daniel said, you cannot enforce attributes at compile time.
But if you want to read the data at runtime, why bother with attributes and reflection at all? You can create an abstract method in your abstract class:
abstract class Base
{
public abstract string Metadata();
}
class Derived1 : Base
{
public override string Metadata()
{
return "Metadata for Derived1";
}
}
class Derived2 : Base // won't compile, since Metadata has not been provided
{
}
The behaviour is slightly different, of course. With this option, you need a reference to an instance of the derived class instead of just the type information itself. On the other hand, it avoids reflection.
As Daniel says you can't force at compile time.
You could add the attribute(s) to the abstract parent and pick them up.
Another option is to add a method to check for the existence of the attrribute in the parent class and throw an exception if not present. Call that from suitable methods.
Came across this old question due to a similar use case. One way to enforce Attribute usage at compile time is by writing an analyzer, similar to what the xunit framework does. here's an example:
https://github.com/xunit/xunit.analyzers/blob/main/src/xunit.analyzers/TheoryMethodMustHaveTestData.cs
Involves a little more effort but does the work.
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.
I have a base class with an attribute and I want to hide it in a derived class. Is there any way to do this other than using reflection?
[Authorize(Roles = "User,Admin,Customs")]
public abstract class ApplicationController : Controller
{
}
// hide the Authorize attribute
public class ErrorController : ApplicationController
{
}
You could override the AuthorizeAttribute with your own class and specify it to not be inherited.
[AttributeUsage(AttributeTargets.Class, Inherited=false)]
public class NonInheritedAuthorizeAttribute : AuthorizeAttribute
{
// Constructors, etc.
}
Now you can specify which class to use, as long as you own ApplicationController.
Removing features inherited from a base class violates the Liskov Substitution Principle. Breaking inheritance in this way usually rears its ugly head with unintended and unexpected consequences—after it's too late to change the root problem.
So even if there is a way, I'll answer that you shouldn't use it the vast majority of the time. Alternatives to inheritance may apply, such as containment (has-a instead of inheritance's is-a) or refactoring the base into a separate interface which both can then implement; or even combine both of these.
If it was a method/prop, you could re-declare (new) the member without the offending attribute. I don't know of a way with class-level attributes.
public new SomeType Foo() { return base.Foo(); }
Depends a bit on what you mean by 'Hide'. You should be able to revoke the authorization like this:
// hide the Authorize attribute
[Authorize(Roles = "")]
public class ErrorController : ApplicationController
{
}
You can specify the 'AttributeUage' attribute on your Attribute class, like this:
[AttributeUsage(AttributeTargets.Class, Inherited=false)]
public class AuthorizeAttribute : Attribute
{
}
Then, classes that derive from the class where you've applied the attribute, will not inherit the attribute.
Ow, now I realize that the Authorize attribute is not a custom attribute.