Skip to content

Instantly share code, notes, and snippets.

@MatthewKing
Last active October 13, 2015 07:08
Show Gist options
  • Save MatthewKing/4158409 to your computer and use it in GitHub Desktop.
Save MatthewKing/4158409 to your computer and use it in GitHub Desktop.
// Copyright Matthew King 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See http://www.boost.org/LICENSE_1_0.txt)
using System;
using System.Globalization;
using System.Linq.Expressions;
using System.Reflection;
/// <summary>
/// Provides various reflection-related methods.
/// </summary>
public static class Reflect
{
/// <summary>
/// Returns the name of the property referred to by the specified property expression.
/// </summary>
/// <typeparam name="TSource">
/// Type containing the property.
/// </typeparam>
/// <typeparam name="TProperty">
/// Type of the property.
/// </typeparam>
/// <param name="propertyExpression">
/// An Expression representing a Func mapping an instance of type TSource to an instance
/// of type TProperty.
/// </param>
/// <returns>
/// The name of the property referred to by the specified property expression.
/// </returns>
public static string GetPropertyName<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyExpression)
{
if (propertyExpression == null)
throw new ArgumentNullException(
"propertyExpression",
"propertyExpression should not be null.");
return GetPropertyInfo<TSource, TProperty>(propertyExpression).Name;
}
/// <summary>
/// Returns a PropertyInfo instance for the property referred to by the specified
/// property expression.
/// </summary>
/// <typeparam name="TSource">
/// Type containing the property.
/// </typeparam>
/// <typeparam name="TProperty">
/// Type of the property.
/// </typeparam>
/// <param name="propertyExpression">
/// An Expression representing a Func mapping an instance of type TSource to an instance
/// of type TProperty.
/// </param>
/// <returns>
/// A PropertyInfo instance for the property referred to by the specified
/// property expression.
/// </returns>
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyExpression)
{
if (propertyExpression == null)
throw new ArgumentNullException(
"propertyExpression",
"propertyExpression should not be null.");
Type sourceType = typeof(TSource);
MemberExpression member = propertyExpression.Body as MemberExpression;
if (member == null)
{
string message = String.Format(
CultureInfo.InvariantCulture,
"Expression '{0}' refers to a method, not a property.",
propertyExpression.ToString());
throw new ArgumentException(message);
}
PropertyInfo propertyInfo = member.Member as PropertyInfo;
if (propertyInfo == null)
{
string message = String.Format(
CultureInfo.InvariantCulture,
"Expression '{0}' refers to a field, not a property.",
propertyExpression.ToString());
throw new ArgumentException(message);
}
if (sourceType != propertyInfo.ReflectedType
&& !sourceType.IsSubclassOf(propertyInfo.ReflectedType))
{
string message = String.Format(
CultureInfo.InvariantCulture,
"Expresion '{0}' refers to a property that is not from type {1}.",
propertyExpression.ToString(),
sourceType);
throw new ArgumentException(message);
}
return propertyInfo;
}
}
// Copyright Matthew King 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See http://www.boost.org/LICENSE_1_0.txt)
using System;
using NUnit.Framework;
[TestFixture]
internal sealed class ReflectTests
{
private sealed class ExampleClass
{
public string field;
public string Method() { return null; }
public string Property { get; set; }
}
[Test]
public void GetPropertyName_ExpressionRefersToAMethod_ThrowsArgumentException()
{
const string message = "Expression 'o => o.Method()' refers to a method, not a property.";
Assert.That(() => Reflect.GetPropertyName<ExampleClass, string>(o => o.Method()),
Throws.TypeOf<ArgumentException>()
.And.Message.Contains(message));
}
[Test]
public void GetPropertyName_ExpressionRefersToAField_ThrowsArgumentException()
{
const string message = "Expression 'o => o.field' refers to a field, not a property.";
Assert.That(() => Reflect.GetPropertyName<ExampleClass, string>(o => o.field),
Throws.TypeOf<ArgumentException>()
.And.Message.Contains(message));
}
[Test]
public void GetPropertyName_ReturnsCorrectValue()
{
var value = Reflect.GetPropertyName<ExampleClass, string>(o => o.Property);
var expected = "Property";
Assert.That(value, Is.EqualTo(expected));
}
[Test]
public void GetPropertyInfo_ExpressionRefersToAMethod_ThrowsArgumentException()
{
const string message = "Expression 'o => o.Method()' refers to a method, not a property.";
Assert.That(() => Reflect.GetPropertyInfo<ExampleClass, string>(o => o.Method()),
Throws.TypeOf<ArgumentException>()
.And.Message.Contains(message));
}
[Test]
public void GetPropertyInfo_ExpressionRefersToAField_ThrowsArgumentException()
{
const string message = "Expression 'o => o.field' refers to a field, not a property.";
Assert.That(() => Reflect.GetPropertyInfo<ExampleClass, string>(o => o.field),
Throws.TypeOf<ArgumentException>()
.And.Message.Contains(message));
}
[Test]
public void GetPropertyInfo_ReturnsCorrectValue()
{
var value = Reflect.GetPropertyInfo<ExampleClass, string>(o => o.Property);
var expected = typeof(ExampleClass).GetProperty("Property");
Assert.That(value, Is.EqualTo(expected));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment