Strongly typed properties declarations - is this code safe?
I'm wondering if following code is "safe". By "safe" I mean that I don't depend on some specific compiler version or undocumented feature. I want to get string with property / field name, but I want to declare it using strong typing (I want the compiler to check if开发者_开发问答 specific field / property exists). My method looks like this:
string GetPropertyName<T>(Expression<Func<T, object>> expression)
{
if (expression.Body is UnaryExpression)
{
var operand = ((UnaryExpression)expression.Body).Operand.ToString();
return operand.Substring(operand.IndexOf(".") + 1);
}
else if (expression.Body is MemberExpression)
{
return ((MemberExpression)expression.Body).Member.Name;
}
else
{
throw new NotImplementedException();
}
}
And here is how I want to use it:
class Foo
{
public string A { get; set; }
public Bar B { get; set; }
}
class Bar
{
public int C { get; set; }
public Baz D { get; set; }
}
class Baz
{
public int E { get; set; }
}
GetPropertyName<Foo>(x => x.A)
GetPropertyName<Foo>(x => x.B)
GetPropertyName<Foo>(x => x.B.C)
GetPropertyName<Foo>(foo => foo.B.D.E)
Thanks in advance for help.
I'm not sure that the output of the ToString
method is guaranteed in any way. The documentation just says that it "returns a textual representation of the Expression
".
(I suspect that the output is unlikely to change across different platforms/versions, but I'd be a bit reluctant to rely on it when your aim is to use strong typing, compile-time checks etc.)
Here's my method that does something similar without using ToString
:
public static string GetPropertyName<T>(Expression<Func<T, object>> e)
{
MemberExpression me;
switch (e.Body.NodeType)
{
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
var ue = e.Body as UnaryExpression;
me = ((ue != null) ? ue.Operand : null) as MemberExpression;
break;
default:
me = e.Body as MemberExpression;
break;
}
if (me == null)
throw new ArgumentException("Expression must represent field or property access.", "e");
var stack = new Stack<string>();
do
{
stack.Push(me.Member.Name);
me = me.Expression as MemberExpression;
} while (me != null);
return string.Join(".", stack); // use "stack.ToArray()" on .NET 3.5
}
I think you code is okay. I don't see any problems. To get a little deep into this, I recommend you read this article and this one, too.
public static string GetPropertyName<T>(Expression<Func<T, object>> e)
{
if (e.Body is MemberExpression)
return ((MemberExpression)e.Body).Member.Name;
else if (e.Body is UnaryExpression)
return ((MemberExpression)((UnaryExpression)e.Body).Operand).Member.Name;
throw new ArgumentException("Expression must represent field or property access.", "e");
}
精彩评论