Attribute that is called by compiler during compilation?

  • Thread starter Thread starter Stuart Carnie
  • Start date Start date
S

Stuart Carnie

I suspect it's unlikely, but you'll never know until you ask, but are there any attributes that would allow us to contribute to
the compiled output?

e.g.

// this class exists in a separate, compiled assembly for the compiler to load during compilation
class MyMethodCompiler : Attribute
{
// This is called during compilation
public override void GenerateMethod(MethodBuilder method)
{
// modify the IL that was generated from the compiler
}
}


// some class in a user assembly
class MyClass
{

[MyMethodCompiler]
public void SomeMethod(...)
{
// User code in method
...
...
...
}
}
 
Alas no. This is not the goal of an attribute.

Code cannot be run at compile time because, well, the code hasn't been built
yet...

Attributes provide metadata which may be used at runtime but is only
available through reflection on a finished assembly or an instance of a
class. The Attribute based classes can have functional methods but are
usually "instantiated" by the process of reflection and an attribute cannot
alter the form of the code with which it is associated.

An attribute that has construction parameters will be created, instantiated,
when the TypeDescriptor.GetAttributes method is called. An attribute with no
constructor parameters will be instantiated at the moment that the
reflection process discovers an attribute of that type in the metadata. If
the attribute is way down on the list, the construction will take place
after the previous attributes have been created.

Once an attribute is instantiated by the process of reflection you can then
call its methods.

Find a little C# example after my signature...

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

namespace StrangeAttribute

{

/// <summary>

/// Summary description for Form1.

/// </summary>

[

Pork(),

Pork("......Plonk")

]

public class Form1 : System.Windows.Forms.Form

{

private System.Windows.Forms.Button button1;

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.Container components = null;

public Form1()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

//

// TODO: Add any constructor code after InitializeComponent call

//

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

this.button1 = new System.Windows.Forms.Button();

this.SuspendLayout();

//

// button1

//

this.button1.Location = new System.Drawing.Point(96, 128);

this.button1.Name = "button1";

this.button1.TabIndex = 0;

this.button1.Text = "Reflect";

this.button1.Click += new System.EventHandler(this.button1_Click);

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.ClientSize = new System.Drawing.Size(292, 266);

this.Controls.Add(this.button1);

this.Name = "Form1";

this.Text = "Form1";

this.ResumeLayout(false);

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form1());

}

private void button1_Click(object sender, System.EventArgs e)

{

System.Diagnostics.Trace.WriteLine("Reflecting");

foreach(Attribute a in TypeDescriptor.GetAttributes(this,true))

{

System.Diagnostics.Trace.WriteLine("Got attribute: "+a.ToString());

if(a.GetType() == typeof(PorkAttribute))

{

((PorkAttribute)a).foo();

}

}

}

}

[

AttributeUsage(AttributeTargets.All, AllowMultiple=true)

]

public class PorkAttribute : Attribute

{

public PorkAttribute()

{

this.Arrgghh("!!");

}

public PorkAttribute(string stuff)

{

MessageBox.Show("This time it worked"+stuff);

}

void Arrgghh(string stuff)

{

MessageBox.Show("Attribute Constructed!!");

}

public void foo()

{

MessageBox.Show("Foo!!");

}

}

}



Stuart Carnie said:
I suspect it's unlikely, but you'll never know until you ask, but are there
any attributes that would allow us to contribute to the compiled output?

e.g.

// this class exists in a separate, compiled assembly for the compiler to
load during compilation
class MyMethodCompiler : Attribute
{
// This is called during compilation
public override void GenerateMethod(MethodBuilder method)
{
// modify the IL that was generated from the compiler
}
}


// some class in a user assembly
class MyClass
{

[MyMethodCompiler]
public void SomeMethod(...)
{
// User code in method
...
...
...
}
}
 
What about the ConditionalAttribute - this does indeed affect compilation and resulting output.

Try the following code and use Lutz's Reflector - you will see CSC.exe was indeed influenced by the [Conditional] attribute.
There is no call to test.MethodTwo() in the resulting IL.

A condition would be the attribute would be compiled in a separate assembly, if it is going to be executed by the compiler, but
given my example below, certainly possible.

************************************

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyTest test = new MyTest();

test.MethodOne();
test.MethodTwo();
}

}

class MyTest
{
public void MethodOne()
{
Console.WriteLine("MethodOne");
}

[Conditional("NOCOMPILE")]
public void MethodTwo()
{
Console.WriteLine("MethodTwo");
}
}
}

************************************
 
"certainly possible" suggests in a future version :) I it doesn't appear to be available today, but you never know what the
future holds.

Cheers,

Stu

Stuart said:
What about the ConditionalAttribute - this does indeed affect
compilation and resulting output.

Try the following code and use Lutz's Reflector - you will see CSC.exe
was indeed influenced by the [Conditional] attribute. There is no call
to test.MethodTwo() in the resulting IL.

A condition would be the attribute would be compiled in a separate
assembly, if it is going to be executed by the compiler, but given my
example below, certainly possible.

************************************

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyTest test = new MyTest();

test.MethodOne();
test.MethodTwo();
}

}

class MyTest
{
public void MethodOne()
{
Console.WriteLine("MethodOne");
}

[Conditional("NOCOMPILE")]
public void MethodTwo()
{
Console.WriteLine("MethodTwo");
}
}
}

************************************

Alas no. This is not the goal of an attribute.

Code cannot be run at compile time because, well, the code hasn't been
built yet...

Attributes provide metadata which may be used at runtime but is only
available through reflection on a finished assembly or an instance of
a class. The Attribute based classes can have functional methods but
are usually "instantiated" by the process of reflection and an
attribute cannot alter the form of the code with which it is associated.

An attribute that has construction parameters will be created,
instantiated, when the TypeDescriptor.GetAttributes method is called.
An attribute with no constructor parameters will be instantiated at
the moment that the reflection process discovers an attribute of that
type in the metadata. If the attribute is way down on the list, the
construction will take place after the previous attributes have been
created.

Once an attribute is instantiated by the process of reflection you can
then call its methods.

Find a little C# example after my signature...
 
Stuart,
A condition would be the attribute would be compiled in a separate assembly, if it is going to be executed by the compiler, but
given my example below, certainly possible.

But the ConditionalAttribute itself doesn't do anything here. It's
simply a hint to the compiler to possibly exclude calls to the method.
All the logic is in the compiler, the attribute is just a dumb class.

You could do the same today for your own attribute by extending one of
the open source C# compilers.


Mattias
 
Indeed - I'm suggesting a 'future' feature. An extensible compiler. How useful would that be!
 
Back
Top