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.
Related
nameof(order.User.Age) return only Age instead of order.User.Age
What is the reason to do it in more restricted way?
If we want only last name we could do something like
public static GetLastName(this string x) {
return string.Split(x, '.').Last();
}
nameof(order.User.Age).GetLastName()
And with one operator we could get both, Age and order.User.Age. But with current implementation we can only get Age. Is there some logic behind this decision? For example, such behavior is necessary for MVC binding
Html.TextBox(nameof(order.User.Age))
Note that if you need/want the "full" name, you could do this:
$"{nameof(order)}.{nameof(User)}.{nameof(Age)}".GetLastName();
as long as all of these names are in the current scope.
Obviously in this case it's not really all that helpful (the names won't be in scope in the Razor call), but it might be if you needed, for example, the full namespace qualified name of a type for a call to Type.GetType() or something.
If the names are not in scope, you could still do the somewhat more clunky:
$"{nameof(order)}.{nameof(order.User)}.{nameof(order.User.Age)}".GetLastName();
-- although chances are at least one of those should be in scope (unless User.Age is a static property).
I had the same problem and implemented a class that acts as a replacement of the nameof() keyword in order to get the full name of the expression being supplied. It's greatly inspired from OK HOSTING answer. It's just all baked and ready to use:
public static class NameOf<TSource>
{
#region Public Methods
public static string Full(Expression<Func<TSource, object>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
{
var unaryExpression = expression.Body as UnaryExpression;
if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert)
memberExpression = unaryExpression.Operand as MemberExpression;
}
var result = memberExpression.ToString();
result = result.Substring(result.IndexOf('.') + 1);
return result;
}
public static string Full(string sourceFieldName, Expression<Func<TSource, object>> expression)
{
var result = Full(expression);
result = string.IsNullOrEmpty(sourceFieldName) ? result : sourceFieldName + "." + result;
return result;
}
#endregion
}
Using it in your code would look like:
class SpeciesFamily
{
public string Name { get; set; }
}
class Species
{
public SpeciesFamily Family { get; set; }
public string Name { get; set; }
}
class Cat
{
public Species Species { get; set; }
}
// Will return a string containing "Species.Family.Name".
var fullName = NameOf<Cat>.Full(c => c.Species.Family.Name);
// Will return a string containing "cat.Species.Name".
var fullNameWithPrefix = NameOf<Cat>.Full("cat", c => c.Species.Name);
Because it is exactly what for it've been invented. As you can read in already linked discussions, here you using the nameof operator as nameof(member-access), of the form E.I<A1…AK>, which will return:
These cases are all resolved using the rules for simple name lookup $7.6.2 or member access $7.6.4. If they succeed in binding, they must bind to one of:
A method-group. This produces an error "To specify the name of a method, you must provide its arguments".
A variable, value, parameter, constant, enumeration-member, property-access, field, event, type-parameter, namespace or type. In this case the result of the nameof operator is simply "I", which is generally the name of the symbol that the argument bound to. There are some caveats…
So in this case it, by its definition, have to evaluate all expressions before all the dots, step by step, and after that evaluate the last one to get its Name:
order.User.Age --> User.Age --> Age
Take a look at this method taken from:
https://github.com/okhosting/OKHOSTING.Data/blob/master/src/PCL/OKHOSTING.Data/Validation/MemberExpression.cs
public static string GetMemberString(System.Linq.Expressions.Expression<Func<T, object>> member)
{
if (member == null)
{
throw new ArgumentNullException("member");
}
var propertyRefExpr = member.Body;
var memberExpr = propertyRefExpr as System.Linq.Expressions.MemberExpression;
if (memberExpr == null)
{
var unaryExpr = propertyRefExpr as System.Linq.Expressions.UnaryExpression;
if (unaryExpr != null && unaryExpr.NodeType == System.Linq.Expressions.ExpressionType.Convert)
{
memberExpr = unaryExpr.Operand as System.Linq.Expressions.MemberExpression;
if(memberExpr != null)
{
return memberExpr.Member.Name;
}
}
}
else
{
//gets something line "m.Field1.Field2.Field3", from here we just remove the prefix "m."
string body = member.Body.ToString();
return body.Substring(body.IndexOf('.') + 1);
}
throw new ArgumentException("No property reference expression was found.", "member");
}
Some of the important purposes of using nameof is to get the last "name" in the expression.
For example nameof parameter when throwing ArgumentNullException:
void Method(string parameter)
{
if (parameter == null) throw new ArgumentNullException(nameof(parameter));
}
MVC Action links
<%= Html.ActionLink("Sign up",
#typeof(UserController),
#nameof(UserController.SignUp))
%>
INotifyPropertyChanged
int p {
get { return this._p; }
set { this._p = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.p)); }
}
More information: https://roslyn.codeplex.com/discussions/570551
I have following class
public class Device
{
[XmlElement("MobileDeviceType")]
public string DeviceType { get; set; }
}
I need extension method called "GetXElementName()" and I need to use the method like below.
string propertyDescription = (new Device()).DeviceType.GetXElementName(); // this shoud return "MobileDeviceType"
As a example
public static class ExtensionMethods
{
public static string GetXElementName<T>(this T source)
{
PropertyInfo prop = source.GetType().GetProperty(source.ToString());
string desc = prop.Name;
object[] attrs = prop.GetCustomAttributes(true);
object attr = attrs[0];
XmlElementAttribute descAttr = attr as XmlElementAttribute;
if (descAttr != null)
{
desc = descAttr.ElementName;
}
return desc;
}
}
Can I know how should I modify the method body to use the "GetXElementName()" method to use like I explained above.
You need to use Expressions to achieve that, because you need to know the member, not the value.
public static class Extensions
{
public static string GetXmlElementName<T, TProperty>(this T obj, Expression<Func<T, TProperty>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
return string.Empty;
var xmlElementAttribute = memberExpression.Member.GetCustomAttribute<XmlElementAttribute>();
if (xmlElementAttribute == null)
return string.Empty;
return xmlElementAttribute.ElementName;
}
}
Usage:
public class MyClass
{
[XmlElement(ElementName = "Test")]
public string MyProperty { get; set; }
}
new MyClass().GetXmlElementName(x => x.MyProperty) // output "Test"
EDIT: another version, without an object instance (see Nyerguds comment)
I guess the most elegant way is make a generic class, with a generic method, so you can call it by specify only the T type parameter (TProperty is taken implicitly).
public class GetXmlElementName<T>
{
public static string From<TProperty>(Expression<Func<T, TProperty>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
return string.Empty;
var xmlElementAttribute = memberExpression.Member.GetCustomAttribute<XmlElementAttribute>();
if (xmlElementAttribute == null)
return string.Empty;
return xmlElementAttribute.ElementName;
}
}
Usage:
GetXmlElementName<MyClass>.From(x => x.MyProperty) // output "Test"
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
}
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.