开发者

What's the best way to define & access selected properties in C#?

From my recent question, I try to centralize the domain model by including some silly log开发者_运维问答ic in domain interface. However, I found some problem that need to include or exclude some properties from validating.

Basically, I can use expression tree like the following code. Nevertheless, I do not like it because I need to define local variable ("u") each time when I create lambda expression. Do you have any source code that is shorter than me? Moreover, I need some method to quickly access selected properties.

public void IncludeProperties<T>(params Expression<Func<IUser,object>>[] selectedProperties)
{
    // some logic to store parameter   
}

IncludeProperties<IUser>
(
    u => u.ID,
    u => u.LogOnName,
    u => u.HashedPassword
);

Thanks,


Lambdas are great for many scenarios - but if you don't want them, perhaps simply don't use them? I hate to say it, but simple strings are tried and tested, especially for scenarios like data binding. If you want fast access, you could look at HyperDescriptor, or there are ways of compiling a delegate to the property accessors, or you can build an Expression from the string and compile it (including a cast to object if you want a known signature, rather than calling the (much slower) DynamicInvoke).

Of course, in most cases even crude reflection is fast enough, and isn't the bottleneck.

I suggest starting with the simplest code, and check it is actually too slow before worrying about it being fast. If it isn't too slow, don't change it. Any of the above options would work otherwise.


Another thought; if you are using Expression, you could do something like:

public void IncludeProperties<T>(
    Expression<Func<T,object>> selectedProperties)
{
    // some logic to store parameter   
}

IncludeProperties<IUser>( u => new { u.ID, u.LogOnName, u.HashedPassword });

and then take the expression apart? A bit tidier, at least... here's some sample code showing the deconstruction:

public static void IncludeProperties<T>(
    Expression<Func<T, object>> selectedProperties)
{
    NewExpression ne = selectedProperties.Body as NewExpression;
    if (ne == null) throw new InvalidOperationException(
          "Object constructor expected");

    foreach (Expression arg in ne.Arguments)
    {
        MemberExpression me = arg as MemberExpression;
        if (me == null || me.Expression != selectedProperties.Parameters[0])
            throw new InvalidOperationException(
                "Object constructor argument should be a direct member");
        Console.WriteLine("Accessing: " + me.Member.Name);
    }
}
static void Main()
{
    IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword });
}

Once you know the MemberInfos (me.Member in the above), building your own lambdas for individual access should be trivial. For example (including a cast to object to get a single signature):

var param = Expression.Parameter(typeof(T), "x");
var memberAccess = Expression.MakeMemberAccess(param, me.Member);
var body = Expression.Convert(memberAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, param);
var func = lambda.Compile();


Here's the shortest expression I can come up with:

public static void IncludeProperties(Expression<Action<IUser>> selectedProperties)
{
    // some logic to store parameter   
}

public static void S(params object[] props)
{
    // dummy method to get to the params syntax
}

[Test]
public void ParamsTest()
{
    IncludeProperties(u => S(
        u.Id,
        u.Name
        ));

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜