How do I define a property to read an attribute from, without instantionating an object?
Suppose I have:
class Person
{
[ColumnAttribute("ID"]
public int Id;
[ColumnAttribute("开发者_开发百科Name"]
public string Name;
[ColumnAttribute("DateOfBirth"]
public date BirthDate;
}
I want to read the attribute on some property but without instantionating the Person object. Say for example I want to read the attribute defined on Name property.But I want it to be like that ReadAttribute(Person.Name) without creating an object.
Why do I want that? because this Person object is a Entity object for a framework I am creating, and I want to be able to define the column on which I want to sort the return from the DAL Layer.
I don't want to pass strings because that way the string will get out of sync when I change the database and so on.
So is this possible? The function of the dal is Person.GetAllByAge(int Age, /somehow here I want to define the sorting/)
If there is another way to fix this problem I will be happy to hear it. I was thinking of using expression tree maybe, but I am stuck there too. thanksEdit:
thank you all for answearing but the question is not about reading attributes.
i want when calling the dal to call something like that Dal.Person.GetAllByAge(25, BirthDate) this will return all the persons which are 25 years old sorted by name this can be done currently by calling Dal.Person.GetAllByAge(25, "DateOfBirth") thanksIn addition to Pete M's answer you could pass the Func<T1,T2>
used in IEnumerable<T>.OrderBy
into your method, and order within your method
public IEnumerable<Person> GetAllByAge<T>(int age, Func<Person,T> orderBy)
{
var people = ... (get your collection of 'age' aged people here)
return people.OrderBy(orderBy);
}
Usage would then be Dal.Person.GetAllByAge(25,p => p.BirthDate)
Yep, I defined an extension method, to make it a bit easier, so i can just call typeof(Person).GetAttributes<CollumnAttribute>()
:
/// <summary>
/// Loads the configuration from assembly attributes
/// </summary>
/// <typeparam name="T">The type of the custom attribute to find.</typeparam>
/// <param name="typeWithAttributes">The calling assembly to search.</param>
/// <returns>An enumeration of attributes of type T that were found.</returns>
public static IEnumerable<T> GetAttributes<T>(this Type typeWithAttributes)
where T : Attribute
{
// Try to find the configuration attribute for the default logger if it exists
object[] configAttributes = Attribute.GetCustomAttributes(typeWithAttributes,
typeof(T), false);
// get just the first one
if (configAttributes != null && configAttributes.Length > 0)
{
foreach (T attribute in configAttributes)
{
yield return attribute;
}
}
}
Is there a specific reason to force ordering on the GetAllByAge()
method itself? Why not just sort it once you get it back? Does the order by logic need to happen server side? I would return a List<Person>
(which you mentioned doing yourself) and use LINQ to order the set as needed, unless I had a really good reason not to:
Dal.Person.GetAllByAge(25).OrderBy(p => p.BirthDate);
This is definitely doable without instantiating a Person
object. You'll want to use Reflection to access the attribute, specifically the GetCustomAttributes
method.
Here's an article for reference.
Your end result may end up looking something like this:
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(typeof(Person)); // Reflection.
Attributes don't allow lambdas as arguments, so p => p.BirthDate
unfortunately isn't possible. In a similar scenario I used enums to link things together.
This worked just fine for my purposes, but still results in some code duplication (being the enum declaration). This does however solve the problem of string literals, and you can now safely refactor your code.
精彩评论