This probably applies to other places, but in WinForms, when I use binding I find many methods want to take the name of the property to bind to. Something like:
class Person
{
public String Name { get { ... } set { ... } }
public int Age { get { ... } set { ... } }
}
class PersonView
{
void Bind(Person p)
{
nameControl.Bind(p,"Name");
ageControl.Bind(p,"Age");
}
}
The big problem I keep having with this is that "Name" and "Age" are specified as strings. This means the compiler is no help if someone renames one of Person's properties. The code will compile fine, but the bindings will be broken.
Is there a standard way of solving this that I've missed? It feels like I need some keyword, maybe called stringof to match the existing typeof. You could use it something like:
ageControl.Bind(p,stringof(p.Age).Name);
stringof could return some class that has properties for getting the full path, part of the path, or the string so you can parse it up yourself.
Is something like this already do-able?
Have a look at this code snippet I've posted in another question, it can help you! (But only, if you are using .NET 3.5)
Best Regards
Oliver Hanappi
You can do that with expression trees, as explained in this question
protected static string GetPropertyName<TSource, TResult>(Expression<Func<TSource, TResult>> expression)
{
if (expression.NodeType == ExpressionType.Lambda && expression.Body.NodeType == ExpressionType.MemberAccess)
{
PropertyInfo prop = (expression.Body as MemberExpression).Member as PropertyInfo;
if (prop != null)
{
return prop.Name;
}
}
throw new ArgumentException("expression", "Not a property expression");
}
...
ageControl.Bind(p, GetPropertyName((Person p) => p.Age));
You can use Expressions to get compiler-checked bindings.
For example, in one of current projects we set up bindings like this:
DataBinder
.BindToObject(this)
.ObjectProperty(c => c.IsReadOnly)
.Control(nameTextBox, n => n.ReadOnly)
.Control(addressControl, n => n.ReadOnly)
Code supporting this style is separated into several classes:
public static class DataBinder
{
public static DataBinderBindingSourceContext<TDataSource> BindToObject<TDataSource>(TDataSource dataSource)
{
return new DataBinderBindingSourceContext<TDataSource>(dataSource);
}
}
public class DataBinderBindingSourceContext<TDataSource>
{
public readonly object DataSource;
public DataBinderBindingSourceContext(object dataSource)
{
DataSource = dataSource;
}
public DataBinderControlContext<TDataSource, TProperty> ObjectProperty<TProperty>(Expression<Func<TDataSource, TProperty>> property)
{
return new DataBinderControlContext<TDataSource, TProperty>(this, property);
}
}
public class DataBinderControlContext<TDataSource, TProperty>
{
readonly DataBinderBindingSourceContext<TDataSource> BindingSourceContext;
readonly string ObjectProperty;
public DataBinderControlContext
(
DataBinderBindingSourceContext<TDataSource> bindingSourceContext,
Expression<Func<TDataSource, TProperty>> objectProperty
)
{
BindingSourceContext = RequireArg.NotNull(bindingSourceContext);
ObjectProperty = ExpressionHelper.GetPropertyName(objectProperty);
}
public DataBinderControlContext<TDataSource, TProperty> Control<TControl>(TControl control, Expression<Func<TControl, TProperty>> property)
where TControl : Control
{
var controlPropertyName = ExpressionHelper.GetPropertyName(property);
control.DataBindings.Add(controlPropertyName, BindingSourceContext.DataSource, ObjectProperty, true);
return this;
}
}
public static class ExpressionHelper
{
public static string GetPropertyName<TResult>(Expression<Func<TResult>> property)
{
return GetMemberNames(((LambdaExpression)property).Body).Skip(1).Join(".");
}
public static string GetPropertyName<T, TResult>(Expression<Func<T, TResult>> property)
{
return GetMemberNames(((LambdaExpression)property).Body).Join(".");
}
static IEnumerable<string> GetMemberNames(Expression expression)
{
if (expression is ConstantExpression || expression is ParameterExpression)
yield break;
var memberExpression = (MemberExpression)expression;
foreach (var memberName in GetMemberNames(memberExpression.Expression))
yield return memberName;
yield return memberExpression.Member.Name;
}
}
public static class StringExtentions
{
public static string Join(this IEnumerable<string> values, string separator)
{
if (values == null)
return null;
return string.Join(separator, values.ToArray());
}
}
You could use reflection to find the name ;-)
This of course would be a circular reference, you'd use the name that you think it is to find the same name (or to not find anything, meaning the property was renamed... But there's an idea (or rather, a trick) : by making a do-nothing reference to the property you wish to use, you'd get compile time confirmation that it is still there. Only problem is if someone merely swap various property names around; in that case, the names still exist (no compile-time error), but have different application-level semantics (possible surprises in the application's output)
Related
"nameof" expression is introduced in Visual Studio 2015 and c# 6
nameof (C# and Visual Basic Reference)
How can u use it or write a similar method in older versions like .net framework 4.
If you're talking about an equivalent for C# before C#6, this will get the job done (in a hacky way) for properties. It can probably be expanded upon to include fields, methods, etc.
public static class TestExtension
{
public static String nameof<T, TT>(this T obj, Expression<Func<T, TT>> propertyAccessor)
{
if (propertyAccessor.Body.NodeType == ExpressionType.MemberAccess)
{
var memberExpression = propertyAccessor.Body as MemberExpression;
if (memberExpression == null)
return null;
return memberExpression.Member.Name;
}
return null;
}
}
Just whipped this up quickly, so there's a lot to be improved, but you use it like this:
public class myClass
{
public string myProp { get; set; }
}
var a = new myClass();
var result = a.nameof(b => b.myProp);
Result contains 'myProp'
Update:
More comprehensive (though still not that pretty)
public static class TestExtension
{
public static String nameof<T, TT>(this Expression<Func<T, TT>> accessor)
{
return nameof(accessor.Body);
}
public static String nameof<T>(this Expression<Func<T>> accessor)
{
return nameof(accessor.Body);
}
public static String nameof<T, TT>(this T obj, Expression<Func<T, TT>> propertyAccessor)
{
return nameof(propertyAccessor.Body);
}
private static String nameof(Expression expression)
{
if (expression.NodeType == ExpressionType.MemberAccess)
{
var memberExpression = expression as MemberExpression;
if (memberExpression == null)
return null;
return memberExpression.Member.Name;
}
return null;
}
}
Accessing static properties/fields:
TestExtension.nameof(() => myClass.MyOtherField)
Accessing parameters within functions:
void func (int a) {
TestExtension.nameof(() => a);
}
To my knowledge there are three options to not have to use a magic string
nameof which requires Visual Studio 2015 (But can be compiled to other versions of the .net framework)
nameof(this.Property)
use a method that takes an expression and returns the property name as found in this post "Get string name of property using reflection"
var propertyName = GetPropertyName(
() => myObject.AProperty); // returns "AProperty"
CallerMemberNameAttribute - (Only available in .net framework 4.5, included because original post said older versions like .net framework 4.0 which I guess includes 4.5) The draw back of this method is it is only useful when you need to string representation of the current method you are operating in.
public string IsChecked {
set{
Console.WriteLine(GetCurrentMemberName()); // prints "IsChecked"
}
}
string GetCurrentMemberName([CallerMemberName] string memberName = "")
{
return memberName;
}
nameOf - Gets resolved at Compiletime - if you decompile, you will see that the compiler just translated the classname (without the Namespace(!)) into a constant string instead.
So be aware!
If you want to get a classe's name use typeof() or GetType() to get the specific (maybe derived) type at Runtime and read the value of
the .Name-Property in .net < C#6.
Read more at MSDN
The nameof operator returns a string representation of the variable you have passed it so nameof(var1) will return "var1", its useful in avoiding code where we have to specificy variable names as strings like in argument exceptions.
In previous versions you could achieve a similar effect using reflection, or expression trees.
#Rob, thank you so much, but the static member access could be for the non-static class members too.
public static class TestExtension {
public static String nameof<T>(this Expression<Func<T, object>> accessor)
{
return nameof(accessor.Body);
}
}
class MyClass {
public Guid MyOtherField;
}
TestExtension.nameof<MyClass>(o=>o.MyOtherField);
and the good news is the Class won't be instantiated. It is useful to access domain layer DTOs.
Is it possible to use an enum with expressions to reflect on the enum values? Consider this hypothetical routine:
public enum Fruit
{
Apple,
Pear
}
public void Foo(Fruit fruit)
{
Foo<Fruit>(() => fruit);
}
public void Foo<T>(Expression<Func<T>> expression)
{
//... example: work with Fruit.Pear and reflect on it
}
Bar() will give me information about the enum, but I want to work with the actual value.
Background: I've been adding some helper methods to return CustomAttribute information for types and wondered if a similar routine could be used for enums.
I'm fully aware you can work with the enum type to get the CustomAttributes that way.
Update:
I use a similar concept in MVC with helper extensions:
public class HtmlHelper<TModel> : System.Web.Mvc.HtmlHelper<TModel>
{
public void BeginLabelFor<TProperty>(Expression<Func<TModel, TProperty>> expression)
{
string name = ExpressionHelper.GetExpressionText(expression);
}
}
In this example name would be the member name of the model. I want to do a similar thing with enums, so name would be the enum 'member'. Is this even possible?
Updated example:
public enum Fruit
{
[Description("I am a pear")]
Pear
}
public void ARoutine(Fruit fruit)
{
GetEnumDescription(() => fruit); // returns "I am a pear"
}
public string GetEnumDescription<T>(/* what would this be in a form of expression? Expression<T>? */)
{
MemberInfo memberInfo;
// a routine to get the MemberInfo(?) 'Pear' from Fruit - is this even possible?
if (memberInfo != null)
{
return memberInfo.GetCustomAttribute<DescriptionAttribute>().Description;
}
return null; // not found or no description
}
You don't need Expressions for this. All you need to know is that enums have a field for each of their values. This means you can do something like:
public static string GetEnumDescription<T>(T enumValue) where T : struct, Enum
{
FieldInfo field = typeof(T).GetField(enumValue.ToString());
if (field != null)
{
var attribute = field.GetCustomAttribute<DescriptionAttribute>();
if (attribute != null)
return attribute.Description;
}
return null; // not found or no description
}
It is possible to do this:
public static void SomeMethod<TFunc>(Expression<TFunc> expr)
{
//LambdaExpression happily excepts any Expession<TFunc>
LambdaExpression lamb = expr;
}
and call it elsewhere passing a lambda for the parameter:
SomeMethod<Func<IQueryable<Person>,Person>>( p=>p.FirstOrDefault());
I would instead like to pass an expression as a parameter to an attribute constructor.
Is it possible to do the below?
class ExpandableQueryAttribute: Attribute {
private LambdaExpression someLambda;
//ctor
public ExpandableQueryMethodAttribute(LambdaExpression expression)
{
someLambda = expression
}
}
//usage:
static LambdaExpression exp =
(Expression<Func<IQueryable<Person>, Person>>)
(p => p.FirstOrDefault());
[ExpandableQueryAttribute(exp)] //error here
// "An attribute argument must be a constant expression, typeof expression
// or array creation expression of an attribute parameter type"
My goal is to specify a method or lambda in the constructor of the attribute(even if I have to declare a full named method and pass the name of the method somehow, that'd be fine to).
Parameter types can change, but it is important that the attribute constructor can take that parameter and in some way be able to assign it to a field of type LambdaExpression
I want the declaration of the lambda/method to be just above the call to the attribute constructor, or inline, so that you don't have to go far to see what is being passed.
So these alternatives would be fine, but no luck getting them to work:
public static ... FuncName(...){...}
[ExpandableQueryAttribute(FuncName)]
// ...
or
//lambdas aren't allowed inline for an attribute, as far as I know
[ExpandableQueryAttribute(q => q.FirstOrDefault())]
// ...
The existing work around is to pass a number ID to the constructor(satisfying the "argument must be a constant" requirement), which is used by the constructor to do a lookup in a dictionary where expressions have been added previously. Was hoping to improve/simplify this, but I have a feeling it doesn't get any better due to limitations on attribute constructors.
how about this:
class ExpandableQueryAttribute : Attribute
{
private LambdaExpression someLambda;
//ctor
public ExpandableQueryAttribute(Type hostingType, string filterMethod)
{
someLambda = (LambdaExpression)hostingType.GetField(filterMethod).GetValue(null);
// could also use a static method
}
}
this should let you assign your lambda to a field and then suck it in at runtime, although in general I would prefer to use something like PostSharp to do this at compile time.
simple usage example
public class LambdaExpressionAttribute : Attribute
{
public LambdaExpression MyLambda { get; private set; }
//ctor
public LambdaExpressionAttribute(Type hostingType, string filterMethod)
{
MyLambda = (LambdaExpression)hostingType.GetField(filterMethod).GetValue(null);
}
}
public class User
{
public bool IsAdministrator { get; set; }
}
public static class securityExpresions
{
public static readonly LambdaExpression IsAdministrator = (Expression<Predicate<User>>)(x => x.IsAdministrator);
public static readonly LambdaExpression IsValid = (Expression<Predicate<User>>)(x => x != null);
public static void CheckAccess(User user)
{
// only for this POC... never do this in shipping code
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace();
var method = stackTrace.GetFrame(1).GetMethod();
var filters = method.GetCustomAttributes(typeof(LambdaExpressionAttribute), true).OfType<LambdaExpressionAttribute>();
foreach (var filter in filters)
{
if ((bool)filter.MyLambda.Compile().DynamicInvoke(user) == false)
{
throw new UnauthorizedAccessException("user does not have access to: " + method.Name);
}
}
}
}
public static class TheClass
{
[LambdaExpression(typeof(securityExpresions), "IsValid")]
public static void ReadSomething(User user, object theThing)
{
securityExpresions.CheckAccess(user);
Console.WriteLine("read something");
}
[LambdaExpression(typeof(securityExpresions), "IsAdministrator")]
public static void WriteSomething(User user, object theThing)
{
securityExpresions.CheckAccess(user);
Console.WriteLine("wrote something");
}
}
static void Main(string[] args)
{
User u = new User();
try
{
TheClass.ReadSomething(u, new object());
TheClass.WriteSomething(u, new object());
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
This is not possible because what you can pass into an attribute needs to fit into the CLR's binary DLL format and there is no way to encode arbitrary object initialization. For the same you you cannot pass a nullable value for example. The restrictions are very strict.
Although you cannot have complex constructor for attributes, in some situation a work-aound is to have a public property for that attribute and update it at run-time.
self point to an object of the class that contains some attributes on its properties. LocalDisplayNameAttribute is a custom attribute.
The following code will set ResourceKey property of my custom attribute class at run-time. Then at that point you can override DisplayName to outpiut whatever text you want.
static public void UpdateAttributes(object self)
{
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(self))
{
LocalDisplayNameAttribute attr =
prop.Attributes[typeof(LocalDisplayNameAttribute)]
as LocalDisplayNameAttribute;
if (attr == null)
{
continue;
}
attr.ResourceKey = prop.Name;
}
}
Use dymanic linq: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
You can make the attribute's constructor take a string which evaluates to an expression.
I have several classes with attributes assigned to them. The one I'm mostly interested in is the FieldLength.MaxLength value.
/// <summary>
/// Users
/// </summary>
[Table(Schema = "dbo", Name = "users"), Serializable]
public partial class Users
{
/// <summary>
/// Last name
/// </summary>
[Column(Name = "last_name", SqlDbType = SqlDbType.VarChar)]
private string _LastName;
[FieldLength(MaxLength=25), FieldNullable(IsNullable=false)]
public string LastName
{
set { _LastName = value; }
get { return _LastName; }
}
}
I need to know if it's possible to write some kind of extension method for the properties in my class to return the MaxLength value of the FieldLength attribute?
For instance. I'd like to be able to write something like the following…
Users user = new Users();
int lastNameMaxLength = user.LastName.MaxLength();
No, this is not possible. You could add an extension method on Users though:
public static int LastNameMaxLength(this Users user) {
// get by reflection, return
}
To save typing, you could further refine Jason's Extension to something like this.
public static void MaxLength<T>(this T obj, Expression<Func<T, object>> property)
This way it will appear on all object (unless you specify a where T restriction) and you have a compile-time safe implementation of the Property Accessor as you would use the code as:
user.MaxLength(u => u.LastName);
No. Because the syntax you propose returns the value of the LastName property and not the property itself.
In order to retrieve and make use of the attributes, you'll need to use reflection which means you need to know the property itself.
As an idea, you could achieve this neatly by using LINQ's Expression library though to resolve the property for the object.
Example syntax you might look for:
var lastNameMaxLength = AttributeResolver.MaxLength<Users>(u => u.LastName);
Where:
public class AttributeResolver
{
public int MaxLength<T>(Expression<Func<T, object>> propertyExpression)
{
// Do the good stuff to get the PropertyInfo from the Expression...
// Then get the attribute from the PropertyInfo
// Then read the value from the attribute
}
}
I've found this class helpful in resolving properties from Expressions:
public class TypeHelper
{
private static PropertyInfo GetPropertyInternal(LambdaExpression p)
{
MemberExpression memberExpression;
if (p.Body is UnaryExpression)
{
UnaryExpression ue = (UnaryExpression)p.Body;
memberExpression = (MemberExpression)ue.Operand;
}
else
{
memberExpression = (MemberExpression)p.Body;
}
return (PropertyInfo)(memberExpression).Member;
}
public static PropertyInfo GetProperty<TObject>(Expression<Func<TObject, object>> p)
{
return GetPropertyInternal(p);
}
}
That's not possible in that form. The best you can manage is a method that takes a lambda expression, gets the property associated with it and then use reflection to obtain the attribute.
int GetMaxLength<T>(Expression<Func<T,string>> property);
And call it like:
GetMaxLength<Users>((u)=>LastName)
You could write an extension method, but it would have to accept a first parameter of PropertyInfo rather than string (since the string itself has no attributes.) It would look something like this:
public static int GetMaxLength(this PropertyInfo prop)
{
// TODO: null check on prop
var attributes = prop.GetCustomeAttributes(typeof(FieldLengthAttribute), false);
if (attributes != null && attributes.Length > 0)
{
MaxLengthAttribute mla = (MaxLengthAttribute)attributes[0];
return mla.MaxLength;
}
// Either throw or return an indicator that something is wrong
}
You then get the property via reflection:
int maxLength = typeof(Users).GetProperty("LastName").GetMaxLength();
I'm playing around with the idea of passing a property assignment to a method as an expression tree. The method would Invoke the expression so that the property gets assigned properly, and then sniff out the property name that was just assigned so I can raise the PropertyChanged event. The idea is that I'd like to be able to use slim auto-properties in my WPF ViewModels and still have the PropertyChanged event fired off.
I'm an ignoramus with ExpressionTrees, so I'm hoping someone can point me in the right direction:
public class ViewModelBase {
public event Action<string> PropertyChanged = delegate { };
public int Value { get; set; }
public void RunAndRaise(MemberAssignment Exp) {
Expression.Invoke(Exp.Expression);
PropertyChanged(Exp.Member.Name);
}
}
The problem is I'm not sure how to call this. This naive attempt was rejected by the compiler for reasons that I'm sure will be obvious to anyone who can answer this:
ViewModelBase vm = new ViewModelBase();
vm.RunAndRaise(() => vm.Value = 1);
EDIT
Thank you #svick for the perfect answer. I moved one little thing around and made it into an extension method. Here's the complete code sample with unit test:
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
MyViewModel vm = new MyViewModel();
bool ValuePropertyRaised = false;
vm.PropertyChanged += (s, e) => ValuePropertyRaised = e.PropertyName == "Value";
vm.SetValue(v => v.Value, 1);
Assert.AreEqual(1, vm.Value);
Assert.IsTrue(ValuePropertyRaised);
}
}
public class ViewModelBase : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public void OnPropertyChanged(string propertyName) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MyViewModel : ViewModelBase {
public int Value { get; set; }
}
public static class ViewModelBaseExtension {
public static void SetValue<TViewModel, TProperty>(this TViewModel vm, Expression<Func<TViewModel, TProperty>> exp, TProperty value) where TViewModel : ViewModelBase {
var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member;
propertyInfo.SetValue(vm, value, null);
vm.OnPropertyChanged(propertyInfo.Name);
}
}
You can't do it this way. First, lambda expressions can be converted only to delegate types or Expression<T>.
If you change the signature of the method (for now ignoring its implementation) to public void RunAndRaise(Expression<Action> Exp), the compiler complains that “An expression tree may not contain an assignment operator”.
You could do it by specifying the property using lambda and the value you want to set it to in another parameter. Also, I didn't figure out a way to access the value of vm from the expression, so you have to put that in another parameter (you can't use this for that, because you need the proper inherited type in the expression):see edit
public static void SetAndRaise<TViewModel, TProperty>(
TViewModel vm, Expression<Func<TViewModel, TProperty>> exp, TProperty value)
where TViewModel : ViewModelBase
{
var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member;
propertyInfo.SetValue(vm, value, null);
vm.PropertyChanged(propertyInfo.Name);
}
Another possibility (and one I like more) is to raise the event from setter specifically using lambda like this:
private int m_value;
public int Value
{
get { return m_value; }
set
{
m_value = value;
RaisePropertyChanged(this, vm => vm.Value);
}
}
static void RaisePropertyChanged<TViewModel, TProperty>(
TViewModel vm, Expression<Func<TViewModel, TProperty>> exp)
where TViewModel : ViewModelBase
{
var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member;
vm.PropertyChanged(propertyInfo.Name);
}
This way, you can use the properties as usual, and you could also raise events for computed properties, if you had them.
EDIT: While reading through Matt Warren's series about implementing IQueryable<T>, I realized I can access the referenced value, which simplifies the usage of RaisePropertyChanged() (although it won't help much with your SetAndRaise()):
private int m_value;
public int Value
{
get { return m_value; }
set
{
m_value = value;
RaisePropertyChanged(() => Value);
}
}
static void RaisePropertyChanged<TProperty>(Expression<Func<TProperty>> exp)
{
var body = (MemberExpression)exp.Body;
var propertyInfo = (PropertyInfo)body.Member;
var vm = (ViewModelBase)((ConstantExpression)body.Expression).Value;
vm.PropertyChanged(vm, new PropertyChangedEventArgs(propertyInfo.Name));
}
Here is a generaic solution that can give you an Action for assignment from an expression to specify the left hand side of assignment, and a value to assign.
public Expression<Action> Assignment<T>(Expression<Func<T>> lvalue, T rvalue)
{
var body = lvalue.Body;
var c = Expression.Constant(rvalue, typeof(T));
var a = Expression.Assign(body, c);
return Expression.Lambda<Action>(a);
}
with this, the code in the question is simply
ViewModelBase vm = new ViewModelBase();
vm.RunAndRaise(Assignment(() => vm.Value, 1));
If you change the definition like
public void RunAndRaise(Expression<Action> Exp) {
Exp.Compile()();
PropertyChanged(Exp.Member.Name);
}
We can also say
//Set the current thread name to "1234"
Assignment(() => Thread.CurrentThread.Name, "1234")).Compile()();
Simple enough, isn't it?
A general solution for the expression tree may not contain an assignment operator issue would be to create a local setter Action and call that one by the Expression:
// raises "An expression tree may not contain an assignment operator"
Expression<Action<string>> setterExpression1 = value => MyProperty = value;
// works
Action<string> setter = value => MyProperty = value;
Expression<Action<string>> setterExpression2 = value => setter(value);
This may not be suited to your exact problem, but I'm hoping this helps someone as this question is kind of the best match for googling that error message.
I'm unsure why exactly the compiler disallows this.
May be u mean Expression.Assign which was added in .net 4.0?