Method chains with nameof operator - c#

If I do nameof(instance.SomeProperty), it evaluates to "SomeProperty".
Is there any way I can get the entire method chain "instance.SomeProperty"?
I know I could do nameof(instance) + "." + nameof(instance.SomeProperty), but is there a better way that's more maintainable?

Is there any way I can get the entire method chain "instance.SomeProperty"?
Nope. You can, however, do something similar to your other solution:
$"{nameof(instance)}.{nameof(instance.SomeProperty)}"
You can try it here.

My 5 cents:
using System;
using System.Linq.Expressions;
public static class Program {
public static void Main() {
Console.WriteLine(Name.Of<A>(x => x.B.Hehe)); // outputs "B.Hehe"
var a = new A();
Console.WriteLine(Name.Of(() => a.B.Hehe)); // outputs "B.Hehe"
}
public class A {
public B B { get; } // property
}
public class B {
public int Hehe; // or field, does not matter
}
}
public static class Name
{
public static string Of(this Expression<Func<object>> expression) => Of(expression.Body);
public static string Of<T>(this Expression<Func<T, object>> expression) => Of(expression.Body);
public static string Of(this Expression expression)
{
switch (expression)
{
case MemberExpression m:
var prefix = Of(m.Expression);
return (prefix == "" ? "" : prefix + ".") + m.Member.Name;
case UnaryExpression u when u.Operand is MemberExpression m:
return Of(m);
default:
return "";
}
}
}

No, there is not. The nameof operator just yields the property (or class, field, etc) at the end of the expression, so nameof(Program.Main) will yield Main, and so does nameof(ConsoleAppliation1.Program.Main).
The nameof operator wasn't meant to do what you ask. It is just prevent passing names around for event handlers, dependency properties, etc. that depend on the sole name of the property / class name. All other fancy stuff you want to do is on your own.
Like M.kazem Akhgary commented, you can do this yourself by constructing the expression yourself:
$"{nameof(instance)}.{nameof(instance.SomeProperty)}"

Related

Is there a way to map Func<T1, bool> to Func<T2, bool>?

So, I was wondering if it possible to do the next thing in c#:
I have a DB model - let's say it is Car:
public class Car {
public string Id {get;set;}
public string Name {get;set}
}
And a DbSet for this type in someDbContext:
public DbSet<Car> Cars {get;set;}
And also I have a CarDto
public class CarDto {
public string Id {get;set;}
public string Name {get;set}
}
And as result we get something like this:
var select = new Func<CarDto, bool>(car => car.Name == "BMW");
// And somehow use this expression for other type Car
someDbContext.Cars.Where(select);
Maybe there is an approach in which I could map these Funcs like this:
var newFunc = mapper.Map<Func<Car, bool>>(select);
Any thoughts?
If you just want to handle rewriting property accesses, you can use an ExpressionVisitor which looks a bit like this:
public class Program
{
public static void Main()
{
Expression<Func<Car, bool>> expr = x => x.Name == "BMW";
var replaced = ReplaceParameter<CarDto>(expr);
}
private static Expression<Func<T, bool>> ReplaceParameter<T>(LambdaExpression expr)
{
if (expr.Parameters.Count != 1)
throw new ArgumentException("Expected 1 parameter", nameof(expr));
var newParameter = Expression.Parameter(typeof(T), expr.Parameters[0].Name);
var visitor = new ParameterReplaceVisitor()
{
Target = expr.Parameters[0],
Replacement = newParameter,
};
var rewrittenBody = visitor.Visit(expr.Body);
return Expression.Lambda<Func<T, bool>>(rewrittenBody, newParameter);
}
}
public class ParameterReplaceVisitor : ExpressionVisitor
{
public ParameterExpression Target { get; set; }
public ParameterExpression Replacement { get; set; }
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression == this.Target)
{
// Try and find a property with the same name on the target type
var members = this.Replacement.Type.GetMember(node.Member.Name, node.Member.MemberType, BindingFlags.Public | BindingFlags.Instance);
if (members.Length != 1)
{
throw new ArgumentException($"Unable to find a single member {node.Member.Name} of type {node.Member.MemberType} on {this.Target.Type}");
}
return Expression.MakeMemberAccess(this.Replacement, members[0]);
}
return base.VisitMember(node);
}
}
We need to deconstruct the LambdaExpression into its body and parameters. We need to create a new parameter which has the correct type, and replace all usages of the old parameter with the new one. This is where the visitor comes in: whenever it sees you access a member on the old parameter, it tries to find the corresponding member on the new parameter, and access that instead.
We then construct a new LambdaExpression, using the rewritten body and the new parameter.
You have a whole bunch of options:
Derive your Dto class from the context class. That way you can use polymorphism as normal.
Extract an interface and implement it in both your Dto and context classes. Same as above then, use polymorphism.
Use duck-typing. In C#, that's done with the dynamic keyword. You lose Intellisense and compile-time error checking, but your code will work.
Reflection. It's a lot of code, it's slow, it's practically a much worse version of #3, but you can cobble it together if you really try.
Something like Automapper will help you map your context to your Dto piece-wise, but it won't help you translate your lambda function filters.

Get JSON PropertyName from C# Class, like "nameof(class.prop)" for json properties?

How would I get the JSON PropertyName of the following class & Property? Something like a "nameof()" equivilent for JSON Properties?
ie, something like
var jsonName = GetJSONPropertyName(SampleClass.SampleClassID); //should return "jsoniD"
public class SampleClass
{
public SampleClass() { }
[JsonProperty(PropertyName = "jsoniD")]
public string SampleClassID { get; set; }
}
A good question would be, how do you pass a property in a type-safe way. Properties are not first-class objects in .NET.
One of the ways would be this:
using System.Linq.Expressions;
// ...
static string GetJsonPropertyName<TC, TP>(Expression<Func<TC, TP>> expr)
{
if (expr.Body is MemberExpression body)
return body.Member.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName;
else
throw new ArgumentException("expect field access lambda");
}
You'll need to call the function like this:
var jsonName = GetJsonPropertyName<SampleClass, string>(x => x.SampleClassID);
Yes, it doesn't feel very natural. Sorry for that.
Thanks to #elgonzo, the code can be simplified like this:
static string GetJsonPropertyName<TC>(Expression<Func<TC, object>> expr)
{
// in case the property type is a value type, the expression contains
// an outer Convert, so we need to remove it
var body = (expr.Body is UnaryExpression unary) ? unary.Operand : expr.Body;
if (body is System.Linq.Expressions.MemberExpression memberEx)
return memberEx.Member.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName;
else
throw new ArgumentException("expect field access lambda");
}
var jsonName = GetJsonPropertyName<SampleClass>(x => x.SampleClassID);
Working Value-Type Expression support based on #Vlad's solution
(with UnaryExpression pattern lifted from this SO POST)
public static string GetJsonPropertyName<T>(Expression<Func<T, object>> expr)
{
if (((expr.Body as UnaryExpression)?.Operand ?? expr.Body) is MemberExpression body)
return body.Member.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName;
else
throw new ArgumentException("expect field access lambda");
}

How can I get property name strings used in a Func of T

I have a scenario where I have to get an array of strings that represent each of the property names used within a Func parameter. Here is an example implementation:
public class CustomClass<TSource>
{
public string[] GetPropertiesUsed
{
get
{
// do magical parsing based upon parameter passed into CustomMethod
}
}
public void CustomMethod(Func<TSource, object> method)
{
// do stuff
}
}
Here would be an example usage:
var customClass = new CustomClass<Person>();
customClass.CustomMethod(src => "(" + src.AreaCode + ") " + src.Phone);
...
var propertiesUsed = customClass.GetPropertiesUsed;
// propertiesUsed should contain ["AreaCode", "Phone"]
The part I'm stuck on in the above is the "do magical parsing based upon parameter passed into CustomMethod."
You should use Expression<Func<>> class instead. The expression contains actual tree, and can easily be complied to get a delegate (which is a func). What You are really trying to do is to look at the body of the expression and reason about it. Expression class provides You with all the neccessary infrastructure.
You'll need to change your CustomMethod to take an Expression<Func<TSource, object>>, and probably subclass the ExpressionVisitor, overriding VisitMember:
public void CustomMethod(Expression<Func<TSource, object>> method)
{
PropertyFinder lister = new PropertyFinder();
properties = lister.Parse((Expression) expr);
}
// this will be what you want to return from GetPropertiesUsed
List<string> properties;
public class PropertyFinder : ExpressionVisitor
{
public List<string> Parse(Expression expression)
{
properties.Clear();
Visit(expression);
return properties;
}
List<string> properties = new List<string>();
protected override Expression VisitMember(MemberExpression m)
{
// look at m to see what the property name is and add it to properties
... code here ...
// then return the result of ExpressionVisitor.VisitMember
return base.VisitMember(m);
}
}
This should get you started in the right direction. Let me know if you need some help figuring out the "... code here ..." part.
Useful links:
Expression Trees
How to Modify Expression Trees
ExpressionVisitor
VisitMember
MemberExpression

Conditional typing in generic method

Consider the following (heavily simplified) code:
public T Function<T>() {
if (typeof(T) == typeof(string)) {
return (T) (object) "hello";
}
...
}
It's kind of absurd to first cast to object, then to T. But the compiler has no way of knowing that the previous test assured T is of type string.
What is the most elegant, idiomatic way of achieving this behavior in C# (which includes getting rid of the stupid typeof(T) == typeof(string), since T is string can't be used)?
Addendum: There is no return type variance in .net, so you can't make a function overload to type string (which, by the way, is just an example, but one reason why association end redefinition in polymorphism, e.g. UML, can't be done in c#). Obviously, the following would be great, but it doesn't work:
public T Function<T>() {
...
}
public string Function<string>() {
return "hello";
}
Concrete Example 1: Because there's been several attacks to the fact that a generic function that tests for specific types isn't generic, I'll try to provide a more complete example. Consider the Type-Square design pattern. Here follows a snippet:
public class Entity {
Dictionary<PropertyType, object> properties;
public T GetTypedProperty<T>(PropertyType p) {
var val = properties[p];
if (typeof(T) == typeof(string) {
(T) (object) p.ToString(this); // magic going here
}
return (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(val);
}
}
Concrete Example 2: Consider the Interpreter design pattern:
public class Expression {
public virtual object Execute() { }
}
public class StringExpression: Expression {
public override string Execute() { } // Error! Type variance not allowed...
}
Now let's use generics in Execute to allow the caller to force a return type:
public class Expression {
public virtual T Execute<T>() {
if(typeof(T) == typeof(string)) { // what happens when I want a string result from a non-string expression?
return (T) (object) do_some_magic_and_return_a_string();
} else if(typeof(T) == typeof(bool)) { // what about bools? any number != 0 should be True. Non-empty lists should be True. Not null should be True
return (T) (object) do_some_magic_and_return_a_bool();
}
}
}
public class StringExpression: Expressiong {
public override T Execute<T>() where T: string {
return (T) string_result;
}
}
If you're making these types of checks in a generic method, I'd rethink your design. The method is obviously not truly generic - if it were, you wouldn't need specific type checking...
Situations like this typically can be handled more cleanly by a redesign. One alternative is often to provide an overload of the appropriate type. Other design alternatives which avoid the type-specific behavior exist, as well, such as Richard Berg's suggestion of passing in a delegate.
using System;
using System.Collections.Generic;
using System.Linq;
namespace SimpleExamples
{
/// <summary>
/// Compiled but not run. Copypasta at your own risk!
/// </summary>
public class Tester
{
public static void Main(string[] args)
{
// Contrived example #1: pushing type-specific functionality up the call stack
var strResult = Example1.Calculate<string>("hello", s => "Could not calculate " + s);
var intResult = Example1.Calculate<int>(1234, i => -1);
// Contrived example #2: overriding default behavior with an alternative that's optimized for a certain type
var list1 = new List<int> { 1, 2, 3 };
var list2 = new int[] { 4, 5, 6 };
Example2<int>.DoSomething(list1, list2);
var list1H = new HashSet<int> { 1, 2, 3 };
Example2<int>.DoSomething<HashSet<int>>(list1H, list2, (l1, l2) => l1.UnionWith(l2));
}
}
public static class Example1
{
public static TParam Calculate<TParam>(TParam param, Func<TParam, TParam> errorMessage)
{
bool success;
var result = CalculateInternal<TParam>(param, out success);
if (success)
return result;
else
return errorMessage(param);
}
private static TParam CalculateInternal<TParam>(TParam param, out bool success)
{
throw new NotImplementedException();
}
}
public static class Example2<T>
{
public static void DoSomething(ICollection<T> list1, IEnumerable<T> list2)
{
Action<ICollection<T>, IEnumerable<T>> genericUnion = (l1, l2) =>
{
foreach (var item in l2)
{
l1.Add(item);
}
l1 = l1.Distinct().ToList();
};
DoSomething<ICollection<T>>(list1, list2, genericUnion);
}
public static void DoSomething<TList>(TList list1, IEnumerable<T> list2, Action<TList, IEnumerable<T>> specializedUnion)
where TList : ICollection<T>
{
/* stuff happens */
specializedUnion(list1, list2);
/* other stuff happens */
}
}
}
/// I confess I don't completely understand what your code was trying to do, here's my best shot
namespace TypeSquarePattern
{
public enum Property
{
A,
B,
C,
}
public class Entity
{
Dictionary<Property, object> properties;
Dictionary<Property, Type> propertyTypes;
public T GetTypedProperty<T>(Property p)
{
var val = properties[p];
var type = propertyTypes[p];
// invoke the cast operator [including user defined casts] between whatever val was stored as, and the appropriate type as
// determined by the domain model [represented here as a simple Dictionary; actual implementation is probably more complex]
val = Convert.ChangeType(val, type);
// now create a strongly-typed object that matches what the caller wanted
return (T)val;
}
}
}
/// Solving this one is a straightforward application of the deferred-execution patterns I demonstrated earlier
namespace InterpreterPattern
{
public class Expression<TResult>
{
protected TResult _value;
private Func<TResult, bool> _tester;
private TResult _fallback;
protected Expression(Func<TResult, bool> tester, TResult fallback)
{
_tester = tester;
_fallback = fallback;
}
public TResult Execute()
{
if (_tester(_value))
return _value;
else
return _fallback;
}
}
public class StringExpression : Expression<string>
{
public StringExpression()
: base(s => string.IsNullOrEmpty(s), "something else")
{ }
}
public class Tuple3Expression<T> : Expression<IList<T>>
{
public Tuple3Expression()
: base(t => t != null && t.Count == 3, new List<T> { default(T), default(T), default(T) })
{ }
}
}
Can you use as here?
T s = "hello" as T;
if(s != null)
return s;
I can't think of an "elegant" way to do this. As you say, the compiler can't know that the conditional has ensured that the type of T is string. As a result, it has to assume that, since there's no generalized way to convert from string to T, it's an error. object to T might succeed, so the compiler allows it.
I'm not sure I'd want an elegant way to express this. Although I can see where it'd be necessary to do explicit type checks like this in some situations, I think I'd want it to be cumbersome because it really is a bit of a hack. And I'd want it to stick out: "Hey! I'm doing something weird here!"
Ok, I took a run at it from several different angles and came up short. I would have to conclude that if your current implementation gets the job done you should take the win and move on. Short of some arcane emissions what you got is what you get.
But the compiler has no way of knowing
that the previous test assured T is of
type string.
Umm.... If I am not mistaken, generics is just code gen. The compiler generates a matching method for each distinct type found in the calling methods. So the compiler does know the type argument for the overload being called. Again; If I am not mistaken.
But overall, i think you are misusing the generic in this case, from what I can see, and as others have stated, there are more appropriate solutions..... which are unnamable unless you post code that completely specifies your requirements.
just my 2 pesos...

How to get the PropertyInfo of a specific property?

I want to get the PropertyInfo for a specific property. I could use:
foreach(PropertyInfo p in typeof(MyObject).GetProperties())
{
if ( p.Name == "MyProperty") { return p }
}
But there must be a way to do something similar to
typeof(MyProperty) as PropertyInfo
Is there? Or am I stuck doing a type-unsafe string comparison?
Cheers.
There is a .NET 3.5 way with lambdas/Expression that doesn't use strings...
using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo
{
public string Bar { get; set; }
}
static class Program
{
static void Main()
{
PropertyInfo prop = PropertyHelper<Foo>.GetProperty(x => x.Bar);
}
}
public static class PropertyHelper<T>
{
public static PropertyInfo GetProperty<TValue>(
Expression<Func<T, TValue>> selector)
{
Expression body = selector;
if (body is LambdaExpression)
{
body = ((LambdaExpression)body).Body;
}
switch (body.NodeType)
{
case ExpressionType.MemberAccess:
return (PropertyInfo)((MemberExpression)body).Member;
default:
throw new InvalidOperationException();
}
}
}
You can use the new nameof() operator that is part of C# 6 and available in Visual Studio 2015. More info here.
For your example you would use:
PropertyInfo result = typeof(MyObject).GetProperty(nameof(MyObject.MyProperty)) ?? throw new Exception();
The compiler will convert nameof(MyObject.MyProperty) to the string "MyProperty" but you gain the benefit of being able to refactor the property name without having to remember to change the string because Visual Studio, ReSharper, and the like know how to refactor nameof() values.
You can do this:
typeof(MyObject).GetProperty("MyProperty")
However, since C# doesn't have a "symbol" type, there's nothing that will help you avoid using string. Why do you call this type-unsafe, by the way?
This is probably the best way:
public static class TypeExtensions
{
public static PropertyInfo? GetProperty<T, TValue>(this T type, Expression<Func<T, TValue>> selector) where T : class
{
Expression expression = selector.Body;
return expression.NodeType == ExpressionType.MemberAccess ? (PropertyInfo)((MemberExpression)expression).Member : null;
}
}
Usage:
myObject.GetProperty(opt => opt.PropertyName);
Reflection is used for runtime type evaluation. So your string constants cannot be verified at compile time.

Categories

Resources