You are passing a string, "not important" to that method. The Type is therefore typeof(string). Which does not have those attributes. Further, even Person doesn't have that attribute: only the MemberInfo (FirstName) has them.
There are ways of doing that by passing an Expression:
public static ColumnNameAttribute[] Read<T>(Expression<Func<T>> func)
{
var member = func.Body as MemberExpression;
if(member == null) throw new ArgumentException(
"Lambda must resolve to a member");
return (ColumnNameAttribute[])Attribute.GetCustomAttributes(
member.Member, typeof(ColumnNameAttribute), false);
}
with
var attrs = AttributeReader.Read(() => FirstName);
However! I should advise that I'm not sure that the Person constructor is an appropriate place for this. Probably needs caching.
If you don't want to use lambdas, then passing a Type and the member-name would work too, i.e.
var attrs = AttributeReader.Read(typeof(Person), "FirstName");
(and do reflection from there) - or mixing with generics (for no real reason):
var attrs = Attribute.Read<Person>("FirstName");
var attrs = AttributeReader.Read(Person);, notvar attrs = AttributeReader.Read(FirstName);?