How to Pass Property as Lambda Expression Parameter?
First, you need to write a code that enables you to pass properties as parameters. It looks a little bit scary but don’t worry.
public static string GetMemberName<T>(Expression<Func<T, object>> expression)
{
return GetMemberName(expression.Body);
}
Through the type Expression<Func<T, object>>
, you pass the lambda expression for the property. T
is the type of the class that holds the property.
The next step of the process is to create a utility method to get the name of the property from the lambda expression.
Build Lambda Expressions Reader
You will need two methods for the job. The main method contains logic to get the name of a property, a void
method or a value type method. If you pass null
expression or not supported expression, an ArgumentException
is thrown.
private static string GetMemberName(Expression expression)
{
if (expression == null)
{
throw new ArgumentException(expressionCannotBeNullMessage);
}
if (expression is MemberExpression)
{
var memberExpression = (MemberExpression) expression;
return memberExpression.Member.Name;
}
if (expression is MethodCallExpression)
{
var methodCallExpression = (MethodCallExpression) expression;
return methodCallExpression.Method.Name;
}
if (expression is UnaryExpression)
{
var unaryExpression = (UnaryExpression) expression;
return GetMemberName(unaryExpression);
}
throw new ArgumentException(invalidExpressionMessage);
}
private static string GetMemberName(UnaryExpression unaryExpression)
{
if (unaryExpression.Operand is MethodCallExpression)
{
var methodExpression = (MethodCallExpression) unaryExpression.Operand;
return methodExpression.Method.Name;
}
return ((MemberExpression) unaryExpression.Operand).Member.Name;
}
In my opinion, these methods are easier to use if they are built as extension methods. Also additionally, I added a method that accepts multiple properties’ lambda expressions. It is implemented through params
operator. To pass a method as a lambda expression, use Expression<Action<T>>
type for method’s parameter.
public static class NameReaderExtensions
{
private static readonly string expressionCannotBeNullMessage = "The expression cannot be null.";
private static readonly string invalidExpressionMessage = "Invalid expression.";
public static string GetMemberName<T>
(this T instance, Expression<Func<T, object>> expression)
{
return GetMemberName(expression.Body);
}
public static List<string> GetMemberNames<T>
(this T instance, params Expression<Func<T, object>>[] expressions)
{
List<string> memberNames = new List<string>();
foreach (var cExpression in expressions)
{
memberNames.Add(GetMemberName(cExpression.Body));
}
return memberNames;
}
public static string GetMemberName<T>
(this T instance, Expression<Action<T>> expression)
{
return GetMemberName(expression.Body);
}
private static string GetMemberName(Expression expression)
{
if (expression == null)
{
throw new ArgumentException(expressionCannotBeNullMessage);
}
if (expression is MemberExpression)
{
var memberExpression = (MemberExpression) expression;
return memberExpression.Member.Name;
}
if (expression is MethodCallExpression)
{
var methodCallExpression = (MethodCallExpression) expression;
return methodCallExpression.Method.Name;
}
if (expression is UnaryExpression)
{
var unaryExpression = (UnaryExpression) expression;
return GetMemberName(unaryExpression);
}
throw new ArgumentException(invalidExpressionMessage);
}
private static string GetMemberName(UnaryExpression unaryExpression)
{
if (unaryExpression.Operand is MethodCallExpression)
{
var methodExpression = (MethodCallExpression) unaryExpression.Operand;
return methodExpression.Method.Name;
}
return ((MemberExpression) unaryExpression.Operand).Member.Name;
}
}
Test Drive of the NameExtensions Utility Class
Client client = new Client();
var propertyNames = client.GetMemberNames
(c => c.FistName, c => c.LastName, c => c.City);
foreach (var cPropertyName in propertyNames)
{
Console.WriteLine(cPropertyName);
}
string nameOfTheMethod = client.GetMemberName(c => c.ToString());
Console.WriteLine(nameOfTheMethod);
As expected on the console is displayed - FirstName
, LastName
, City
and ToString
.
Improve PropertiesAsserter Configuration by Usage of Property Lambda Expressions
In summary, the main purpose of the PropertiesAsserter
is to assert all properties of an object against an expected version. However, you should be able to configure it to skip the verification of some of the properties because you may not know what the expected value is - such as DateTime
properties, history fields and so on.
In the first implementation of the utility, skip configuration of the properties not to be asserted, their names were passed as string
s.
public class ObjectToAssertValidator : PropertiesValidator<ObjectToAssertValidator, ObjectToAssert>
{
public void Validate(ObjectToAssert expected, ObjectToAssert actual)
{
this.Validate(expected, actual, "FirstName");
}
}
As you can assume, the later approach is error-prompt because of the possibility of typo errors and renaming of the properties.
The primary method of the PropertiesAsserter
can be refactored to accept params
of properties’ lambda expressions. Internally, it will use the new lambda expressions’ utility to get the properties names.
public void Assert<T>(T expectedObject, T realObject,
params Expression<Func<T, object>>[] propertiesNotToCompareExpressions)
{
PropertyInfo[] properties = realObject.GetType().GetProperties();
List<string> propertiesNotToCompare =
expectedObject.GetMemberNames(propertiesNotToCompareExpressions);
foreach (PropertyInfo currentRealProperty in properties)
{
if (!propertiesNotToCompare.Contains(currentRealProperty.Name))
{
PropertyInfo currentExpectedProperty =
expectedObject.GetType().GetProperty(currentRealProperty.Name);
string exceptionMessage =
string.Format("The property {0} of class {1} was not as expected.",
currentRealProperty.Name, currentRealProperty.DeclaringType.Name);
if (currentRealProperty.PropertyType != typeof(DateTime) &&
currentRealProperty.PropertyType != typeof(DateTime?))
{
MSU.Assert.AreEqual(currentExpectedProperty.GetValue(expectedObject, null),
currentRealProperty.GetValue(realObject, null), exceptionMessage);
}
else
{
DateTimeAssert.AreEqual(
currentExpectedProperty.GetValue(expectedObject, null) as DateTime?,
currentRealProperty.GetValue(realObject, null) as DateTime?,
DateTimeDeltaType.Minutes,
5);
}
}
}
}
Here is the improved configuration code.
public class ObjectToAssertAsserter : PropertiesAsserter<ObjectToAssertAsserter, ObjectToAssert>
{
public void Assert(ObjectToAssert expected, ObjectToAssert actual)
{
this.Assert(expected,
actual,
e => e.LastName,
e => e.FirstName,
e => e.PoNumber);
}
}
So Far in the C# Series
1. Implement Copy Paste C# Code
2. MSBuild TCP IP Logger C# Code
3. Windows Registry Read Write C# Code
4. Change .config File at Runtime C# Code
5. Generic Properties Validator C# Code
6. Reduced AutoMapper- Auto-Map Objects 180% Faster
7. 7 New Cool Features in C# 6.0
8. Types Of Code Coverage- Examples In C#
9. MSTest Rerun Failed Tests Through MSTest.exe Wrapper Application
10. Hints For Arranging Usings in Visual Studio Efficiently
11. 19 Must-Know Visual Studio Keyboard Shortcuts – Part 1
12. 19 Must-Know Visual Studio Keyboard Shortcuts – Part 2
13. Specify Assembly References Based On Build Configuration in Visual Studio
14. Top 15 Underutilized Features of .NET
15. Top 15 Underutilized Features of .NET Part 2
16. Neat Tricks for Effortlessly Format Currency in C#
17. Assert DateTime the Right Way MSTest NUnit C# Code
18. Which Works Faster- Null Coalescing Operator or GetValueOrDefault or Conditional Operator
19. Specification-based Test Design Techniques for Enhancing Unit Tests
20. Get Property Names Using Lambda Expressions in C#
21. Top 9 Windows Event Log Tips Using C#
If you enjoy my publications, feel free to SUBSCRIBE
Also, hit these share buttons. Thank you!
Source Code
Reference
CodeProject
The post Get Property Names Using Lambda Expressions in C# appeared first on Automate The Planet.
All images are purchased from DepositPhotos.com and cannot be downloaded and used for free.
License Agreement