2
 [System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
    sealed class ColumnName : Attribute
    {
        // See the attribute guidelines at 
        //  http://go.microsoft.com/fwlink/?LinkId=85236

        readonly string Column;

        // This is a positional argument
        public ColumnName(string columnName)
        {
            this.Column = columnName;
        }
    }

    public class Comment
    {
        [ColumnName("ID1")]
        public int Id;
        [ColumnName("NAME1")]
        public string Name;
        [ColumnName("TEST1")]
        public string Test;
    }

In this code you can see I have create a class comment which have an attribute ColumnName. ColumnName is my custom class which I used to define the attirubte.

Now I am looking for a sollution to find the ColumnName value for all the properties.

public static List<T> ExecuteReader<T>(string str)
        {
            var res = typeof(T);

            return new List<T>();
        }

I tried run some Stack Overflow code on my issue but it doesn't work well. What thing I am missing in my code?

rene
  • 41,474
  • 78
  • 114
  • 152
Anirudha Gupta
  • 9,073
  • 9
  • 54
  • 79

1 Answers1

5

Given

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = true)]
public sealed class ColumnNameAttribute : Attribute
{
    public readonly string Column;

    public ColumnNameAttribute(string columnName)
    {
        this.Column = columnName;
    }
}

(by convention attributes should have a name ending in Attribute, and note that I've restricted the AttributeTargets to Propertyes and Fields) you can

public static class ColumnsCache<T>
{
    public static readonly IReadOnlyDictionary<MemberInfo, string> Columns = BuildColumnsDictionary();

    public static Dictionary<MemberInfo, string> BuildColumnsDictionary()
    {
        var dict = new Dictionary<MemberInfo, string>();

        var members = typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance)
            .Where(x => x.MemberType == MemberTypes.Field || x.MemberType == MemberTypes.Property);

        foreach (MemberInfo member in members)
        {
            var attr = member.GetCustomAttribute<ColumnNameAttribute>(true);

            if (attr != null)
            {
                dict.Add(member, attr.Column);
            }
        }

        return dict;
    }
}

(note the trick: we are caching the list of column names (and of fields/properties having the ColumnNameAttribute) through the usage of a generic static class. The .NET runtime will create various distinct ColumnsCache<T1>, ColumnsCache<T2>, ColumnsCache<T3>, each one with a different dictionary of columns)

Then you can

var cols = ColumnsCache<Comment>.Columns;
var colNames = cols.Values;

The cols variable will reference a dictionary MemberInfo -> string (colum name), while the colNames is a IEnumerable<string> with only the column names. If you want to use reflection with a MemberInfo you have to check if the MemberInfo is a FieldInfo or a PropertyInfo, cast it and use the FieldInfo or PropertyInfo.

xanatos
  • 109,618
  • 12
  • 197
  • 280