I need property name to be extracted form Func please help me if its possible. Thanks.
public void Converter<T>(Func<T,Ojbect> F)
{
}
public class Tester
{
void main()
{
String Name = Converter<User>(m=>m.Id);
//Name should be equal to "Id"
}
}
What you need is:
public static string GetPropertyName<T>(Expression<Func<T>> property)
{
var memberExpress = property.Body as MemberExpression;
return memberExpress.Member.Name;
}
Which you can then call using:
var user = new User();
string name = GetPropertyName(() => user.Name);
Or even:
public static string GetPropertyName<T, TValue>(Expression<Func<T, TValue>> property)
{
var memberExpress = property.Body as MemberExpression;
return memberExpress.Member.Name;
}
Which you can call using:
string name = GetPropertyName<User, string>(u => u.Id);
Related
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"
This question already has answers here:
How can I get the name of a variable passed into a function?
(23 answers)
Closed 7 years ago.
Is it possible to create a function that returns the name of variable like .ToString() return the string value of a variable.
static class myExten
{
public static string ToName(this object o)
{
///some code that returns the name
}
}
static void Main()
{
string country = "India";
string variableName = country.ToName();
}
Many thanks for your attention.
Edit
As my question is being marked duplicate, I am trying to explain how my qestion is diffrent
I have a generic function that returns a bool value(given below)
static public bool stateNameExists(string name)
{
return SQL_Functions.AlreadyExists("**state_name**", table, name);
}
public static bool AlreadyExists(string column, string table, string value)
{
string qry = "select count(" + column + ") from " + table + " where " + column + " = '"+value+"'";
string result = execute_scaller(qry);
try
{
if (Convert.ToInt16(result) > 0)
{
return true;
}
}
catch
{
return false;
}
return false;
}
Please pay attention at stateNameExists function. In this function I am hardcoding the column name "state_name"
I have a model class
class stateModel
{
public int id [get; set;}
public string state_name {get; set;}
}
I want to pass the name of column using model object like this
SQL_Functions.AlreadyExists(obj.state_name.GetName(), table, name);
that's why I asked for an extension function.
P.S: I can not use c# 6.0 tricks here.
Note: If the question is still duplicate/already answered then please provide its link. Many and Many thanks.
If I get you right, you would need to do something like this:
PropertyHelper.GetName<stateModel>(x=>x.state_name)
and receive stringified name of property here: "state_name".
We use a property helper class for getting property names, you can try this implementation:
public class PropertyHelper
{
public static string GetName<T>(Expression<Func<T>> expression)
{
return GetName(expression.Body);
}
public static string GetName<T>(Expression<Func<T, object>> expression)
{
return GetName(expression.Body);
}
public static string GetName<T, TProperty>(Expression<Func<T, TProperty>> expression)
{
return GetName(expression.Body);
}
public static Type GetType<T>(Expression<Func<T, object>> expression)
{
return GetMemberExpression(expression.Body).Type;
}
public static Type GetType<T, TProperty>(Expression<Func<T, TProperty>> expression)
{
return GetMemberExpression(expression.Body).Type;
}
private static MemberExpression GetMemberExpression(Expression expression)
{
var getMemberExpression = expression as MemberExpression;
if (getMemberExpression != null)
return getMemberExpression;
if (IsConversion(expression))
{
var unaryExpression = expression as UnaryExpression;
if (unaryExpression != null)
return GetMemberExpression(unaryExpression.Operand);
}
return null;
}
private static string GetName(Expression expression)
{
return string.Join(".", GetNames(expression));
}
private static IEnumerable<string> GetNames(Expression expression)
{
var memberExpression = GetMemberExpression(expression);
if (memberExpression == null)
yield break;
foreach (var memberName in GetNames(memberExpression.Expression))
yield return memberName;
yield return memberExpression.Member.Name;
}
private static bool IsConversion(Expression expression)
{
return (expression.NodeType == ExpressionType.Convert
|| expression.NodeType == ExpressionType.ConvertChecked);
}
}
in c# 6, you can use nameof operator, but not within an extension method
static class myExten
{
public static string ToName(this object o)
{
return nameof(o);
}
}
this will always returns "o", i.e. the name of the variable in this method
the best you can do is something such:
static void Main()
{
string country = "India";
string variableName = nameof(country);
}
I am trying to copy the behavior of Entity Framework in creating the query from expression and i found my way using ExpressionVisitor when getting the property of the model by using Attribute
this is what i got so far
internal class NVisitor : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
private readonly Type _type;
public NVisitor(Type type)
{
_type = type;
_parameter = Expression.Parameter(type);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType == MemberTypes.Property)
{
var memberName = node.Member.Name;
PropertyInfo otherMember = _type.GetProperty(memberName);
var ncols = node.Member.GetCustomAttributes(typeof(NColumn), true);
if (ncols.Any())
{
var ncol = (NColumn)ncols.First();
otherMember = _type.GetProperty(ncol.Name);
}
var inner = Visit(node.Expression);
return Expression.Property(inner, otherMember);
}
return base.VisitMember(node);
}
}
i have an attribute NColumn that indicates the real name of the property from table column so i mark the property of the model by Attribute
public class BonusTypeX
{
[NColumn("BonusTypeName")]
public string Name { get; set; }
}
now when im trying to get the expression,
[TestMethod]
public void ExpressionTesting2()
{
string searchKey = "Xmas";
Expression<Func<BonusTypeX, bool>> expression = x => x.Name.Contains(searchKey);
Type t = typeof(tbl_BonusType);
var body = new NVisitor(t).Visit(expression.Body);
string a = string.Join(".", body.ToString().Split('.').Skip(1));
Assert.AreEqual("BonusTypeName.Contains(\"Xmas\")", a);
}
i got this
BonusTypeName.Contains(value(Payroll.Test.Administration.TestRepositories+<>c__DisplayClass13).searchKey)
what i am expecting to get is
BonusTypeName.Contains("Xmas")
is there any method that gets the expression string? i am using
string a = string.Join(".", body.ToString().Split('.').Skip(1));
which i think it might be wrong.. :)
any help would be appreciated.
Local variable are captured in a compiler generated class at runtime, this explains the Payroll.Test.Administration.TestRepositories+<>c__DisplayClass13).searchKey part. To get the generated field's value in your expression you must explicitly replace it's value when visiting the expression:
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType == MemberTypes.Property)
{
var memberName = node.Member.Name;
PropertyInfo otherMember = _type.GetProperty(memberName);
var ncols = node.Member.GetCustomAttributes(typeof(NColumn), true);
if (ncols.Any())
{
var ncol = (NColumn)ncols.First();
otherMember = _type.GetProperty(ncol.Name);
}
var inner = Visit(node.Expression);
return Expression.Property(inner, otherMember);
}
if (node.Member.MemberType == MemberTypes.Field)
{
if (node.Expression is ConstantExpression)
{
var owner = ((ConstantExpression)node.Expression).Value;
var value = Expression.Constant(((FieldInfo)node.Member).GetValue(owner));
return value;
}
}
return base.VisitMember(node);
}
I have a common problem, that I am trying to get round in a specific way.
Basically with Winforms, I am trying to set the "DisplayMember" and "ValueMember" of controls in a form. You would normally set it like so:
this.testCombobox.DisplayMember = "PropertyOne";
this.testCombobox.ValueMember = "PropertyTwo";
I want to rewrite this as follows:
this.testCombobox.DisplayMember = ClassOne.GetPropertyName(c => c.PropertyOne);
this.testCombobox.ValueMember = ClassOne.GetPropertyName(c => c.PropertyTwo);
(NOTE: the 2 method calls need to be static, to save creating objects here)
All of my classes that I am trying to do this, inherit from a base class "BaseObject", so I have added a method to it as follows:
public static string GetPropertyName<T, P>(Expression<Func<T, P>> action) where T : class
{
MemberExpression expression = action.Body as MemberExpression;
return expression.Member.Name;
}
However, in order to use this, I need to write the following code instead:
this.testCombobox.DisplayMember = BaseObject.GetPropertyName((ClassOne c) => c.PropertyOne);
My question is, how would I rewrite the method BaseObject.GetPropertyName to achieve what I want? I feel I am very close but cannot think how to change it.
Your current GetPropertyName method leaves open the generic T. Hence, the compiler cannot resolve it compile-time since you do not specify it when you use the method.
However, if you make your base class generic, AND specify the T in the derived class, AND specify to use the method of the derived class (and not the base class), then it works.
Like this:
public class BaseClass<T> {
public static string GetPropertyName<P>(Expression<Func<T, P>> action) {
MemberExpression expression = action.Body as MemberExpression;
return expression.Member.Name;
}
}
public class ClassOne : BaseClass<ClassOne> {
public string PropertyOne { get; set; }
}
public static class Test {
public static void test() {
var displayMember = ClassOne.GetPropertyName(x => x.PropertyOne);
}
}
I created a Helper class to extract Proprty Name
public static class PropertySupport
{
public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
{
throw new ArgumentException("Invalide Expression", "propertyExpression");
}
return memberExpression.Member.Name;
}
}
And you can use it as Follows :
PropertySupport.ExtractPropertyName(() => DateTime.Now)
it will return "Now"
EDIT
Here is a test console app:
public static class PropertySupport
{
public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
{
throw new ArgumentException("", "propertyExpression");
}
return memberExpression.Member.Name;
}
}
public class MyClass
{
public MyClass PropertyOne { get; set; }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(PropertySupport.ExtractPropertyName(() => new MyClass().PropertyOne));
Console.ReadKey();
}
}
I would suggest the following in generic helper:
public static class GenericHelper<TEntity> {
public static string GetPropertyName<TProperty>(Expression<Func<TEntity, TProperty>> propertyExpression) {
return propertyExpression.GetPropertyName();
}
}
and the following in Extensions for common usage:
public static class ReflectionExtensions {
public static PropertyInfo GetProperty<TEntity, TProperty>(this Expression<Func<TEntity, TProperty>> source) {
//TODO: check TEntity, if needed. Now it's ignored
var member = source.Body as MemberExpression;
if (member == null) {
throw new ArgumentException(String.Format(
"Expression '{0}' refers to a method, not a property.", source));
}
var propertyInfo = member.Member as PropertyInfo;
if (propertyInfo == null) {
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.", source));
}
return propertyInfo;
}
public static string GetPropertyName<TEntity, TProperty>(this Expression<Func<TEntity, TProperty>> source) {
return source.GetProperty().Name;
}
}
AddOptional<tblObject>(x =>x.Title, objectToSend.SupplementaryData);
private static void AddOptional<TType>(Expression<Func<TType,string>> expr, Dictionary<string, string> dictionary)
{
string propertyName;
string propertyValue;
Expression expression = (Expression)expr;
while (expression.NodeType == ExpressionType.Lambda)
{
expression = ((LambdaExpression)expression).Body;
}
}
In Above code i would like to get actual value of property title, not ony propert name , is it possible ?
private static void Main(string[] args)
{
CompileAndGetValue<tblObject>(x => x.Title, new tblObject() { Title = "test" });
}
private static void CompileAndGetValue<TType>(
Expression<Func<TType, string>> expr,
TType obj)
{
// you can still get name here
Func<TType, string> func = expr.Compile();
string propretyValue = func(obj);
Console.WriteLine(propretyValue);
}
However, you must be aware that this can be quite slow. You should measure how it performs in your case.
If you don't like to pass your object:
private static void Main(string[] args)
{
var yourObject = new tblObject {Title = "test"};
CompileAndGetValue(() => yourObject.Title);
}
private static void CompileAndGetValue(
Expression<Func<string>> expr)
{
// you can still get name here
var func = expr.Compile();
string propretyValue = func();
Console.WriteLine(propretyValue);
}