Dynamic declaration in attribute property

As part of an ORM microplatform I'm developing, I'm defining a generic class that exclusively implements tight coupling (1 record x 1 object).

public class Course : MicroEntity<Course>
{
    public string fullname { get; set; }
    public string shortname { get; set; }
    public string summary { get; set; }
    public string format { get; set; }
    [...]
}

To define the behavior of this class, I have a Attribute that contains all boot characteristics:

[MicroEntity(
    TableName = "mdl_course",
    IdentifierColumnName = "ID",
    IsReadOnly = true,
    UseDistributedCaching = true)]
public class Course : MicroEntity<Course>
{
    public string fullname { get; set; }
    public string shortname { get; set; }
    public string summary { get; set; }
    public string format { get; set; }
    [...]
}

I recently implemented a DatabaseAdapter engine to allow agnostic connection to databases different:

public abstract class BaseAdapter
{
    internal abstract void CheckDatabaseEntities<T>() where T : MicroEntity<T>;
    internal abstract void SetSqlStatements<T>() where T : MicroEntity<T>;
    internal abstract void SetConnectionString<T>() where T : MicroEntity<T>;
    internal abstract void RenderSchemaMicroEntityNames<T>() where T : MicroEntity<T>;
    internal abstract BaseDynamicParameters Parameters<T>(object obj) where T : MicroEntity<T>;
    internal abstract DbConnection Connection(string connectionString);
}

From there, I declare adapters for different banks. At the moment, I own adapters for Oracle and MySql.

Question

I would like to be able to declare the adapter as a property of the Attribute :

[MicroEntity(
    TableName = "mdl_course",
    IdentifierColumnName = "ID",
    IsReadOnly = true,
    Adapter = new InternalAdapters.MySql.Adapter();
    UseDistributedCaching = true)]
public class Course : MicroEntity<Course>
{
    [...]

However the use of new() is not allowed. Which model would better serve this type of behavior?

Author: Maniero, 2015-10-06

2 answers

The problem is that attributes do not support dynamic object initialization. There are two alternatives:

1. Mark the attribute with the adapter type

[MicroEntity(
    TableName = "mdl_course",
    IdentifierColumnName = "ID",
    IsReadOnly = true,
    Adapter = typeof(InternalAdapters.MySql.Adapter),
    UseDistributedCaching = true)]

2. Mark the attribute with an enumeration

[MicroEntity(
    TableName = "mdl_course",
    IdentifierColumnName = "ID",
    IsReadOnly = true,
    Adapter = Adapter.MySql,
    UseDistributedCaching = true)]

I am strongly in favour of the former, especially since you have virtually no limits to inject new adapters into the application when this is desired.

When reading the attribute, initialization would be quite simple:

var course = new Course();
var atributoMicroEntity = course.GetType().GetAttribute<MicroEntityAttribute>();
if (atributoMicroEntity != null) 
{
    var adaptador = Activator.CreateInstance(atributoMicroEntity.Adapter);
}
 5
Author: Leonel Sanches da Silva, 2015-10-06 18:43:47

I've seen this problem solved using a Type (I don't remember where now, but I'm sure I've seen it more than once).

public class MicroEntityAttribute : Attribute
{
    public Type Adapter { get; set; }
}

[MicroEntity(Adapter = typeof(InternalAdapters.MySql.Adapter))]
public class SomeClass {}

The expression new Class() is not a constant, but typeof(Class) is - and therefore can be used to initialize an attribute.

The attribute interpreter should then initialize an adapter instance using the Activator, and throwing an exception if you don't have a public constructor without parameters.

 6
Author: dcastro, 2015-10-06 18:47:28