Maybe my question weird... I wonderd if it possible to use reflection on a phrase.
I tried to make comparison with reflection in C#. Until now I passed the name of the property as string and the value as object, like that: Cmp("foo", "abc").
In this way I have to check if foo is existing property in the class, and check if the value type match the property type (in the example above foo is string property, and the value is string). This way works fine!
I just wonder if it possible to send phrase as parameter and analize it with reflection or something simmilar.
I mean, as in the example above instead of calling the function like that Cmp("foo", "abc") just call the function like this Cmp(A.foo == "abc") (A is class that have foo propery), then analize that the property is foo and the value is "abc".
I know its sounds weird, and its not necessary for me. Its just for the idea.
Is it possible?
EDIT
If I was not clear, I have wrote the Cmp(string, string) method, and it works fine!
I just want to know if there is way to write the Cmp method like this: Cmp(A.foo == "abc"). That the parameter is a phrase.
EDIT 2
For example you can do something like it in C. You can create macro like that:
#define Cmp(phrase) printf(##phrase)
Then if you call it like Cmp(A.foo == "abc") the output will be:
A.foo == "abc"
Like pass the whole phrase as parameter and analize it. I know that macro is pre-compile thing, I just want to know if there is something like that in C#
You can use expression trees to describe an expression like bar.Foo == "abc". Here is a simple example that assumes the you have a class named Bar that has a property named Foo:
String FormatExpression<T>(Expression<Func<T, Boolean>> expression) {
if (expression == null)
throw new ArgumentNullException("expression");
var body = expression.Body as BinaryExpression;
if (body == null)
throw new ArgumentException(
"Expression body is not a binary expression.", "expression");
return body.ToString();
}
Calling
FormatExpression((Bar bar) => bar.Foo == "abc")
will return the string
(bar.Foo == "abc")
This extension method goes through all (readable, public) properties of the object it's called on, checks for a property with the given name on that property and compares the values.
public static class CmpExtension
{
public static bool Cmp<T, TValue>(this T obj, string propertyName, TValue value)
where TValue : class
{
var properties = obj.GetType().GetProperties()
.Where(p => p.CanRead);
foreach (var property in properties)
{
var propertyValue = property.GetValue(obj, null);
var childProperty = property.PropertyType.GetProperties()
.Where(p => p.CanRead)
.FirstOrDefault(p => p.Name == propertyName);
if (childProperty == null) continue;
var childPropertyValue = childProperty.GetValue(propertyValue, null);
return childPropertyValue == value;
}
return false;
}
}
By using this, you can do:
public class Foo
{
public Bar Bar { get; set; }
}
public class Bar
{
public string Value { get; set; }
}
public static void Main(string[] args)
{
var foo = new Foo { Bar = new Bar { Value = "Testing" } };
foo.Cmp("Value", "Testing"); // True
}
To use the alternative syntax use:
public static class CmpExtension
{
public static bool Cmp<T>(this T obj, Func<T, bool> func)
{
return func(obj);
}
}
Using this, you can do
public static void Main(string[] args)
{
var foo = new Foo { Bar = new Bar { Value = "Testing" } };
foo.Cmp(f => f.Bar.Value == "Testing"); // True
}
Related
I have an object lets call it ObjectA
and that object has 10 properties and those are all strings.
var myObject = new {Property1="",Property2="",Property3="",Property4="",...}
is there anyway to check to see whether all these properties are null or empty?
So any built-in method that would return true or false?
If any single of them is not null or empty then the return would be false. If all of them are empty it should return true.
The idea is I do not want to write 10 if statement to control if those properties are empty or null.
Thanks
You can do it using Reflection
bool IsAnyNullOrEmpty(object myObject)
{
foreach(PropertyInfo pi in myObject.GetType().GetProperties())
{
if(pi.PropertyType == typeof(string))
{
string value = (string)pi.GetValue(myObject);
if(string.IsNullOrEmpty(value))
{
return true;
}
}
}
return false;
}
Matthew Watson suggested an alternative using LINQ:
return myObject.GetType().GetProperties()
.Where(pi => pi.PropertyType == typeof(string))
.Select(pi => (string)pi.GetValue(myObject))
.Any(value => string.IsNullOrEmpty(value));
I suppose you want to make sure that all properties are filled in.
A better option is probably by putting this validation in the constructor of your class and throw exceptions if validation fails. That way you cannot create a class that is invalid; catch exceptions and handle them accordingly.
Fluent validation is a nice framework (http://fluentvalidation.codeplex.com) for doing the validation. Example:
public class CustomerValidator: AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Property1).NotNull();
RuleFor(customer => customer.Property2).NotNull();
RuleFor(customer => customer.Property3).NotNull();
}
}
public class Customer
{
public Customer(string property1, string property2, string property3)
{
Property1 = property1;
Property2 = property2;
Property3 = property3;
new CustomerValidator().ValidateAndThrow();
}
public string Property1 {get; set;}
public string Property2 {get; set;}
public string Property3 {get; set;}
}
Usage:
try
{
var customer = new Customer("string1", "string", null);
// logic here
} catch (ValidationException ex)
{
// A validation error occured
}
PS - Using reflection for this kind of thing just makes your code harder to read. Using validation as shown above makes it explicitly clear what your rules are; and you can easily extend them with other rules.
The following code returns if any property is not null.
return myObject.GetType()
.GetProperties() //get all properties on object
.Select(pi => pi.GetValue(myObject)) //get value for the property
.Any(value => value != null); // Check if one of the values is not null, if so it returns true.
Here you go
var instOfA = new ObjectA();
bool isAnyPropEmpty = instOfA.GetType().GetProperties()
.Where(p => p.GetValue(instOfA) is string) // selecting only string props
.Any(p => string.IsNullOrWhiteSpace((p.GetValue(instOfA) as string)));
and here's the class
class ObjectA
{
public string A { get; set; }
public string B { get; set; }
}
A slightly different way of expressing the linq to see if all string properties of an object are non null and non empty:
public static bool AllStringPropertyValuesAreNonEmpty(object myObject)
{
var allStringPropertyValues =
from property in myObject.GetType().GetProperties()
where property.PropertyType == typeof(string) && property.CanRead
select (string) property.GetValue(myObject);
return allStringPropertyValues.All(value => !string.IsNullOrEmpty(value));
}
Note if you've got a data structural hierarchy and you want to test everything in that hierarchy, then you can use a recursive method. Here's a quick example:
static bool AnyNullOrEmpty(object obj) {
return obj == null
|| obj.ToString() == ""
|| obj.GetType().GetProperties().Any(prop => AnyNullOrEmpty(prop.GetValue(obj)));
}
To only check if all properties are null:
bool allPropertiesNull = !myObject.GetType().GetProperties().Any(prop => prop == null);
you can use reflection and extension methods to do this.
using System.Reflection;
public static class ExtensionMethods
{
public static bool StringPropertiesEmpty(this object value)
{
foreach (PropertyInfo objProp in value.GetType().GetProperties())
{
if (objProp.CanRead)
{
object val = objProp.GetValue(value, null);
if (val.GetType() == typeof(string))
{
if (val == "" || val == null)
{
return true;
}
}
}
}
return false;
}
}
then use it on any object with string properties
test obj = new test();
if (obj.StringPropertiesEmpty() == true)
{
// some of these string properties are empty or null
}
No, I don't think there is a method to do exactly that.
You'd be best writing a simple method that takes your object and returns true or false.
Alternatively, if the properties are all the same, and you just want to parse through them and find a single null or empty, perhaps some sort of collection of strings would work for you?
You can try the following query :
if the object is "referenceKey" (where few properties may be null )
referenceKey.GetType().GetProperties().Where(x => x.GetValue(referenceKey) == null)
I need to count the properties where the value is set to not Null, so I have used the following query :
var countProvidedReferenceKeys = referenceKey.GetType().GetProperties().Where(x => x.GetValue(referenceKey) != null).Count();
I'm working on a bit of code which has an end purpose of letting you use a property expression to set the value of a property with similar syntax to passing a variable as an out or ref parameter.
Something along the lines of:
public static foo(()=>Object.property, value);
And Object.Property will be assigned the value of value.
I'm using the following code to get the owining object of the property:
public static object GetOwningObject<T>(this Expression<Func<T>> #this)
{
var memberExpression = #this.Body as MemberExpression;
if (memberExpression != null)
{
var fieldExpression = memberExpression.Expression as MemberExpression;
if (fieldExpression != null)
{
var constExpression = fieldExpression.Expression as ConstantExpression;
var field = fieldExpression.Member as FieldInfo;
if (constExpression != null) if (field != null) return field.GetValue(constExpression.Value);
}
}
return null;
}
So this would, when used on a property expression like ()=>Object.Property, give back the instance of 'Object'. I'm somewhat new to using property expressions, and there seems to be many different ways to accomplish things, but I want to extend what I have so far, so that given an expression such as ()=>Foo.Bar.Baz it will give the Bar, not Foo. I always want the last containing object in the expression.
Any ideas? Thanks in advance.
What you have to do is to traverse through property chain to the most outer object.
The sample below is rather self explanatory and shows that the extension method would work for chained fields as well as properties:
class Foo
{
public Bar Bar { get; set; }
}
class Bar
{
public string Baz { get; set; }
}
class FooWithField
{
public BarWithField BarField;
}
class BarWithField
{
public string BazField;
}
public static class LambdaExtensions
{
public static object GetRootObject<T>(this Expression<Func<T>> expression)
{
var propertyAccessExpression = expression.Body as MemberExpression;
if (propertyAccessExpression == null)
return null;
//go up through property/field chain
while (propertyAccessExpression.Expression is MemberExpression)
propertyAccessExpression = (MemberExpression)propertyAccessExpression.Expression;
//the last expression suppose to be a constant expression referring to captured variable ...
var rootObjectConstantExpression = propertyAccessExpression.Expression as ConstantExpression;
if (rootObjectConstantExpression == null)
return null;
//... which is stored in a field of generated class that holds all captured variables.
var fieldInfo = propertyAccessExpression.Member as FieldInfo;
if (fieldInfo != null)
return fieldInfo.GetValue(rootObjectConstantExpression.Value);
return null;
}
}
[TestFixture]
public class Program
{
[Test]
public void Should_find_root_element_by_property_chain()
{
var foo = new Foo { Bar = new Bar { Baz = "text" } };
Expression<Func<string>> expression = () => foo.Bar.Baz;
Assert.That(expression.GetRootObject(), Is.SameAs(foo));
}
[Test]
public void Should_find_root_element_by_field_chain()
{
var foo = new FooWithField { BarField = new BarWithField { BazField = "text" } };
Expression<Func<string>> expression = () => foo.BarField.BazField;
Assert.That(expression.GetRootObject(), Is.SameAs(foo));
}
}
If your project is an MVC 5 project and you have a reference to the assembly System.Web.Mvc You could use the following:
Some time ago I wrote an extension method to easily create a multiselect dropdown (based on bootstrap 4) and it looked something like this:
public static MvcHtmlString MultiSelectFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
/*The challenge I faced here was that the expression you passed could very well be nested, so in order overcome this, I decompiled the dll to see how MVC does it, and I found this piece of code.*/
string expressionText = System.Web.Mvc.ExpressionHelper.GetExpressionText((LambdaExpression)expression);
System.Web.Mvc.ModelMetadata metadata = System.Web.Mvc.ModelMetadata.FromStringExpression(expressionText, htmlHelper.ViewData);
}
The metadata object has a Property called PropertyName and another property called Container which is a reference to the instance of the container object.
Is there a way I can make the following db query builder generic?
private IQueryable<Foo> ByName(IQueryable<Foo> dbQuery, Query query)
{
string[] searchTerms = query.Data.Replace(" ","").ToLower().Split(',');
if (query.Exclude)
{
return dbQuery.Where(x => searchTerms.All(
y => y != x.Name.Replace(" ", "").ToLower()));
}
return dbQuery.Where(x => searchTerms.Any(
y => y == x.Name.Replace(" ", "").ToLower()));
}
I've got the same function for lots of different properties of Foo. ByCounty, ByTown, ByStreet etc etc.
I've written some functions that return linq before like the following
public Expression<Func<Foo, bool>> FoosAreWithinDistanceFromGeocode(
double distance, Geocode geocode)
{
double distanceSquare = distance * distance;
return foo => ( SqlFunctions.Square((double)(
foo.Address.Geocode.Easting - geocode.Easting)) +
SqlFunctions.Square((double)(fooAddress.Geocode.Northing -
geocode.Northing)) ) <= distanceSquare;
}
But I can't seem to find if the Linq-to-SQL stuff can't use generics or if it's possible to pass properties as generics and that kind of thing.
EDIT: I have this working generically for a single search term.
Where [query.Data == "Foo1"]
return dbQuery.Where(SearchMatch("Name", query.Data));
public Expression<Func<Foo, bool>> SearchMatch(string propertyName, string searchTerm)
{
var foo = Expression.Parameter(typeof(Foo), "foo");
var prop = Expression.Property(foo, propertyName);
var search = Expression.Constant(searchTerm);
var equal = Expression.Equal(prop, search);
return Expression.Lambda<Func<Foo, bool>>(equal, foo);
}
Anyone have any ideas how to make it work for an array of strings?
You need to define an interface that exposes the properties that you want to access, like so:
public interface IHaveName
{
string Name { get; }
}
Then, on your classes, you would implement the interface:
public class Foo : IHaveName
If you're using the classes generated from a DBML file, these classes are marked with the partial keyword so implementing the interface is as simple as creating a new file, and inserting:
public partial class Foo : IHaveName
Since the property is already declared as public in the other .cs file generated from the .dbml file, the interface is implemented implicitly.
Finally, you would rewrite your ByName method to take a generic type parameter with a constraint that it implement your interface IHaveName:
private IQueryable<T> ByName<T>(IQueryable<T> dbQuery, Query query)
where T : IHaveName
{
// Everything else is the same.
For your other properties (and methods which use them), you could aggregate them together into one interface, or separate them out, depending on your needs.
Based on your edit, if you want to create an expression dynamically, you don't have to give up compile-time safety:
public Expression<Func<Foo, bool>> SearchMatch(
Expression<Func<Foo, string>> property, string searchTerm)
{
var foo = Expression.Parameter(typeof(Foo), "foo");
// Get the property info from the property expression.
var prop = Expression.Property(foo,
(property.Body as MemberExpression).Member as PropertyInfo);
var search = Expression.Constant(searchTerm);
var equal = Expression.Equal(prop, search);
return Expression.Lambda<Func<Foo, bool>>(equal, foo);
}
Which you then call like so:
var expression = SearchMatch(f => f.Name, "searchTerm");
This ensures that the properties that you are passing to SearchMatch actually exist on Foo. Note if you wanted to make this generic for other scalar property types, you would do the following:
public Expression<Func<Foo, bool>> SearchMatch<T>(
Expression<Func<Foo, T>> property, T searchTerm)
{
var foo = Expression.Parameter(typeof(Foo), "foo");
// Get the property info from the property expression.
var prop = Expression.Property(foo,
(property.Body as MemberExpression).Member as PropertyInfo);
var search = Expression.Constant(searchTerm);
var equal = Expression.Equal(prop, search);
return Expression.Lambda<Func<Foo, bool>>(equal, foo);
}
If I understood what you are trying to achieve reflection might help you. At least if you play nice. Here's a simplified but working example
internal class Program
{
private class Data
{
public string Name { get; set; }
public string Address { get; set; }
public override string ToString()
{
return String.Format("My name is {0} and I'm living at {1}", Name, Address);
}
}
static Expression<Func<Data,bool>> BuildExpression(PropertyInfo prop, IQueryable<string> restrict)
{
return (data) => !restrict.Any(elem => elem == prop.GetValue(data, null));
}
static IQueryable<Data> FilterData(IQueryable<Data> input, Expression<Func<Data, bool>> filter)
{
return input.Where(filter);
}
public static void Main (string[] args)
{
List<Data> list = new List<Data>()
{
new Data {Name = "John", Address = "1st Street"},
new Data {Name = "Mary",Address = "2nd Street"},
new Data {Name = "Carl", Address = "3rd Street"}
};
var filterByNameExpression = BuildExpression(typeof (Data).GetProperty("Name"),
(new List<string> {"John", "Carl"}).AsQueryable());
var filterByAddressExpression = BuildExpression(typeof(Data).GetProperty("Address"),
(new List<string> { "2nd Street"}).AsQueryable());
IQueryable<Data> filetedByName = FilterData(list.AsQueryable(), filterByNameExpression);
IQueryable<Data> filetedByAddress = FilterData(list.AsQueryable(), filterByAddressExpression);
Console.WriteLine("Filtered by name");
foreach (var d in filetedByName)
{
Console.WriteLine(d);
}
Console.WriteLine("Filtered by address");
foreach (var d in filetedByAddress)
{
Console.WriteLine(d);
}
Console.ReadLine();
}
Hovewer, I'\m almost sure it won't work with LINQ-to-SQL. One way to workaround it is to materialize the IQueryable before passing it to such filtering methods (e.g. by calling ToList on them).
I want to make a cloning or mapping function where I can specify (once) which properties to copy to the target object.
The whole point here was a usage that looks something like this
(inspired by using GroupBy),
var botchedOrder = db.BuildingOrders.Find(id);
var redo = db.BuildingOrders.Create();
botchedOrder.MapTo(redo, x => new { x.BasePrice, x.FileAttachments, x.Notes });
This is over my head, but I was guessing at something like this,
public static void MapTo<TObject, TProps>(
this TObject source,
TObject target,
Action<TProps> properties) //?
{
//copy the defined properties from source to target somehow?
//originally I thought I could make an array of delegates..
}
If this works then I can more easily handle different sets of properties in different ways when I am explicitly cloning or mapping objects. I'd like to stick w/ .NET to do this.
EDIT: forgot to indicate void
I'd recommend looking at AutoMapper since it kind of solves same kinds of problems. Also, different ORM sources (like Massive, Petapoco etc.) all have some implementations (since they need to map data from a DB to an object).
Basically, it works either using reflection - to iterate over given fields/properties and set them to another object (also via refleciton). There are approaches to dynamic method generation using IL Generator or Expression Trees that wrap all the reflection code into one nice and fast method generated and compiled at runtime (thus giving performance boost).
Another way to do would be using dynamics or Dictionaries instead of anonymous class - that would remove "anonimity" problem and would just require to map specific keys on to properties - may be done with reflection again (using for example [MappingAttribute("Key")] for distinction - attribute is a fiction, just to give a general idea).
This is the most succinct form I can think of without dropping down to reflection, but it does involve repeating property names, so I'm not sure if it's exactly what you want.
public static void MapTo<TObject>(this TObject source, TObject target, params Action<TObject, TObject>[] properties)
{
foreach (var property in properties)
{
property(source, target);
}
}
Called like:
void Copy(FooBar source, FooBar target)
{
source.MapTo(target, (s,t) => t.Foo = s.Foo,
(s,t) => t.Bar = s.Bar,
(t,s) => t.Baz = s.Baz);
}
class FooBar
{
public string Foo { get; set; }
public string Bar { get; set; }
public string Baz { get; set; }
}
However, it's more verbose that just doing:
void Copy(FooBar source, FooBar target)
{
target.Foo = source.Foo;
target.Bar = source.Bar;
target.Baz = source.Baz;
}
Is there anything else going on in your copy that make the last example invalid? If not, I would just keep it simple and go for that.
Here is a basic dynamic mapper I wrote. I used a slightly different approach as I extended object and instead of specifying the properties, used ignore properties.
public static class ObjectExtensions
{
public static void CopyFrom(this object Instance, object Source)
{
ObjectExtensions.CopyFrom(Instance, Source, false, null);
}
public static void CopyFrom(this object Instance,
object Source,
IEnumerable<string> IgnoreProperties)
{
ObjectExtensions.CopyFrom(Instance, Source, false, IgnoreProperties);
}
public static void CopyFrom(this object Instance,
object Source,
bool ThrowOnPropertyMismatch,
IEnumerable<string> IgnoreProperties)
{
Type sourceType = Source.GetType();
BindingFlags publicInstanceFlags = BindingFlags.Public
| BindingFlags.Instance;
PropertyInfo[] sourceProperties =
sourceType.GetProperties(publicInstanceFlags);
Type instanceType = Instance.GetType();
foreach (PropertyInfo sourceProperty in sourceProperties)
{
if (IgnoreProperties == null
|| (IgnoreProperties.Count() > 0
&& !IgnoreProperties.Contains(sourceProperty.Name)))
{
PropertyInfo instanceProperty =
instanceType.GetProperty(sourceProperty.Name, publicInstanceFlags);
if (instanceProperty != null
&& instanceProperty.PropertyType == sourceProperty.PropertyType
&& instanceProperty.GetSetMethod() != null
&& instanceProperty.GetSetMethod().IsPublic)
{
instanceProperty.SetValue(Instance,
sourceProperty.GetValue(Source, null),
null);
}
else
if (ThrowOnPropertyMismatch
&& instanceProperty.PropertyType != sourceProperty.PropertyType)
{
throw new InvalidCastException(
string.Format("Unable to cast source {0}.{1} to destination {2}.{3}.",
Source.GetType().Name,
sourceProperty.Name,
Instance.GetType().Name,
instanceProperty.Name));
}
}
}
}
A common way of doing this is by using expression trees which can represent the way certain types should map to one another. A primitive stripped down example of such is:
public static void MapTo<TInput, TOutput>(this TInput input, TOutput output, Expression<Func<TInput, TOutput, bool>> expression)
where TInput : class
where TOutput : class
{
if (expression == null)
throw new ArgumentNullException("expression");
Stack<Expression> unhandeledExpressions = new Stack<Expression>();
unhandeledExpressions.Push(expression.Body);
while (unhandeledExpressions.Any())
{
Expression unhandeledExpression = unhandeledExpressions.Pop();
switch (unhandeledExpression.NodeType)
{
case ExpressionType.AndAlso:
{
BinaryExpression binaryExpression = (BinaryExpression)unhandeledExpression;
unhandeledExpressions.Push(binaryExpression.Left);
unhandeledExpressions.Push(binaryExpression.Right);
}
break;
case ExpressionType.Equal:
{
BinaryExpression binaryExpression = (BinaryExpression)unhandeledExpression;
MemberExpression leftArgumentExpression = binaryExpression.Left as MemberExpression;
MemberExpression rightArgumentExpression = binaryExpression.Right as MemberExpression;
if (leftArgumentExpression == null || rightArgumentExpression == null)
throw new InvalidOperationException("Can only map to member expressions");
output.GetType().GetProperty(leftArgumentExpression.Member.Name).SetValue(
output, input.GetType().GetProperty(rightArgumentExpression.Member.Name).GetValue(input, null), null);
}
break;
default:
throw new InvalidOperationException("Expression type not supported");
}
}
}
}
which can be used in the following way:
class SourceType
{
public string Name { get; set; }
public int Number { get; set; }
}
class DestinationType
{
public string CustName { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
var source = new SourceType()
{
Name = "Test",
Number = 22
};
var destination = new DestinationType();
source.MapTo(destination, (src, dst) => dst.CustName == src.Name && dst.Age == src.Number);
bool assert = source.Name == destination.CustName && source.Number == destination.Age;
}
}
The advantage of this approach is that this allows you to define your own mapping 'language' which you can make as complex/extensive as you want.
Still I recommend you to use a pre-built solution like AutoFaq or AutoMapper. Good luck
ok, I think I have something working using an Expression and Reflection.
thing1.MapTo(thing2, x => new { x.Prop1, x.Prop2 });
and
public static void MapTo<T, P>(
this T source, T target, Expression<Func<T, P>> expr)
{
(expr.Body as NewExpression).Members.ToList()
.ForEach(m => source.Copy(target, m.Name));
}
public static void Copy<T>(this T source, T target, string prop)
{
var p = typeof(T).GetProperty(prop);
p.SetValue(target, p.GetValue(source, null), null);
}
I'm not sure the methods have the best names but it's a start and it allows the usage I was hoping for. Any problems with this approach?
I looked and everywhere are many examples how to do property name resolution, but I didn't find that would solve my usage.
My idea of User looks like this:
class Entity<T> where T : class
{
public static String GetName<T>(Expression<Func<T, object>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
}
class User : Entity<User>
{
public String UserName { get; set; }
public DateTime LastLoggedOn { get; set; }
}
Question: How to implement property name resolution if I want to use it like this?
Debug.Assert("UserName" == User.GetField(x => x.UserName));
Debug.Assert("LastLoggedOn" == User.GetField(x => x.LastLoggedOn));
Any help would be appreciated. Thanks.
Notes: I could do var u = new User(); and then u.GetName(() => u.UserName) but in my case, I don't have an instance of the entity
EDIT 1: Thanks to Darin, I updated my code. I need to get LastLoggedOn work too.
Debugging shows, that value of expr is {x => Convert(x.LastLoggedOn)} (don't know what the Convert means)
InvalidCastException was unhandled
Unable to cast object of type 'System.Linq.Expressions.UnaryExpression' to type 'System.Linq.Expressions.MemberExpression'.
EDIT 2/Answer: After some debugging I've composed this "solution". I don't like it, but it seems to work.
public static string GetName(Expression<Func<T, object>> expression)
{
MemberExpression memberExp = expression.Body as MemberExpression;
if (memberExp != null)
return memberExp.Member.Name;
// for DateTime
UnaryExpression unaryExp = expression.Body as UnaryExpression;
if (unaryExp != null)
{
memberExp = unaryExp.Operand as MemberExpression;
if (memberExp != null)
return memberExp.Member.Name;
}
throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression");
}
Just remove the <T> from the GetName static method and you are good to go (the compiler should have warned you about this by the way):
public class Entity<T> where T : class
{
public static string GetName(Expression<Func<T, object>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
}
public class User: Entity<User>
{
public String UserName { get; set; }
}
Now you can write:
string name = User.GetName(x => x.UserName);
You can call your static method on Entity<T>:
string name = Entity<User>.GetName<User>(u => u.UserName);
You have made both the method and the class generic, both taking a type parameter. You probably only want the class to be generic, because it looks like that is how you are using it.