1

I am creating a base class. I want that if it is inherited by some derived class it must apply an attribute else throw a compilation error. is it possible?

public class MyAttribte : Attribute
{
    public string TestString {get; set; }
}

public class Base
{
}

/*Attribute must be applied else throw compile time error.*/
[MyAttribte]
public class Derived : Base { }
abatishchev
  • 98,240
  • 88
  • 296
  • 433
D J
  • 6,908
  • 13
  • 43
  • 75
  • 4
    Not possible at compile time. Why not use abstract/interface features instead? – leppie Jan 11 '13 at 06:02
  • because framework do not support it :(. – D J Jan 11 '13 at 06:03
  • 2
    @DJ if you could elaborate on hwo you're goinng to use this behaviour, you could possibly get some ideas instead of trying using attributes this way – horgh Jan 11 '13 at 06:09
  • Not possible directly... But creative approaches for particular cases are possible - i.e. see [Custom compiler warnings](http://stackoverflow.com/questions/154109/custom-compiler-warnings) that reuses Obsolete attribute (as sample of approach, I don't think it is directly apply to your case). – Alexei Levenkov Jan 11 '13 at 06:17

2 Answers2

3

You cannot compel, but you can check and throw exception at runtime if Attribute is not specified.

var d1 = new Derived1(); // OK
var d2 = new Derived2(); // throw error at run-time

public class Base
{
    public Base()
    {
        CheckCustomAttribute();

    }

    private void CheckCustomAttribute()
    {
        if (!(this.GetType() == typeof(Base))) // Ingore Base for attribute
        {
            //  var attr = System.Attribute.GetCustomAttributes(this.GetType()).SingleOrDefault(t=>t.GetType() == typeof(CustomAttribute));
            var attr = System.Attribute.GetCustomAttributes(this.GetType()).SingleOrDefault(t => typeof(CustomAttribute).IsAssignableFrom(t.GetType())); // to include derived type of Custom attribute also
            if (attr == null)
            {
                throw new Exception(String.Format("Derived class {0} doesnot apply {1} attribute", this.GetType().Name, typeof(CustomAttribute).Name));
            }
        }
    }
}

[CustomAttribute]
class Derived1 : Base
{
}

class Derived2 : Base
{
}
class CustomAttribute : System.Attribute
{
}
Tilak
  • 30,108
  • 19
  • 83
  • 131
1

You can do this at compile-time by using PostSharp. AOP frameworks which use static code weaving after compilation (also known as the process of postcompilation), provide API for verifying your code design. I've created simple example to demonstrate this. Define your attribute

public class MyAttribute : Attribute
{

}

Next goes class, to which you want to apply this attribute. I'll comment out attribute to get an error.

//[MyAttribute]
internal class Program
{
    private static void Main(string[] args)
    {
        Console.WriteLine("Hello World");
    }
}

Now crate your Aspect. It will check if any MyAttribute is present at Program at postcompile time and if not - populate an error message.

[Serializable]
public class MyValidationAspect : AssemblyLevelAspect
{
    public override bool CompileTimeValidate(_Assembly assembly)
    {
        IEnumerable<object> myAttributes = typeof (Program).GetCustomAttributes(inherit: true)
                                                           .Where(atr => atr.GetType() == typeof (MyAttribute));

        if (!myAttributes.Any())
            Message.Write(MessageLocation.Of(typeof (Program)), SeverityType.Error, "DESIGN1",
                          "You haven't marked {0} with {1}", typeof (Program), typeof (MyAttribute));

        return base.CompileTimeValidate(assembly);
    }
}

Then define this aspect on assembly level, like this:

[assembly: MyValidationAspect]

So now, when I try to build solution, I'll get a error:

enter image description here

PostSharpPlay.exe is the name of my console assembly. If I remove comment before MyAttribute - the solution compiles and I get no errors.

enter image description here

Ilya Ivanov
  • 23,148
  • 4
  • 64
  • 90