indexed switch statement, or equivalent? .net, C# - c#

I want to build a method which accepts a string param, and an object which I would like to return a particular member of based on the param. So, the easiest method is to build a switch statement:
public GetMemberByName(MyObject myobj, string name)
{
switch(name){
case "PropOne": return myobj.prop1;
case "PropTwo": return myobj.prop2;
}
}
This works fine, but I may wind up with a rather large list... So I was curious if there's a way, without writing a bunch of nested if-else structures, to accomplish this in an indexed way, so that the matching field is found by index instead of falling through a switch until a match is found.
I considered using a Dictionary<string, something> to give fast access to the matching strings (as the key member) but since I'm wanting to access a member of a passed-in object, I'm not sure how this could be accomplished.
I'm specifically trying to avoid reflection etc in order to have a very fast implementation. I'll likely use code generation, so the solution doesn't need to be small/tight etc.
I originally was building a dictionary of but each object was initializing it. So I began to move this to a single method that can look up the values based on the keys- a switch statement. But since I'm no longer indexed, I'm afraid the continuous lookups calling this method would be slow.
SO: I am looking for a way to combine the performance of an indexed/hashed lookup (like the Dictionary uses) with returning particular properties of a passed-in object. I'll likely put this in a static method within each class it is used for.

Here's a quick mockup of something that could work for any class (using reflection rather than a switch statement):
public static object GetMemberByName<T>(T obj, string name)
{
PropertyInfo prop = typeof(T).GetProperty(name);
if(prop != null)
return prop.GetValue(obj, null);
throw new ArgumentException("Named property doesn't exist.");
}
Or an Extension Method version (which will still work on any object type):
public static object GetMemberByName<T>(this T obj, string name)
{
PropertyInfo prop = typeof(T).GetProperty(name);
if(prop != null)
return prop.GetValue(obj, null);
throw new ArgumentException("Named property doesn't exist.");
}
Obviously there's some additional error checking you might want to do, but this would be a start.
I also returned the type object from the methods for a reason. This allows the caller to handle casting the value however they see fit (if they need to cast at all).

Here's an easy way you can use a dictionary:
Dictionary<string, Func<MyObject, object>> propertyNameAssociations;
private void BuildPropertyNameAssociations()
{
propertyNameAssociations = new Dictionary<string, Func<MyObject, object>>();
propertyNameAssociations.Add("PropOne", x => x.prop1);
propertyNameAssociations.Add("PropTwo", x => x.prop2);
}
public object GetMemberByName(MyObject myobj, string name)
{
if (propertyNameAssociations.Contains(name))
return propertyNameAssociations[name](myobj);
else
return null;
}

There are a few options you can try.
Option 1: Have the object store the property values dynamically.
public GetMemberByName(MyObject myobj, string name)
{
return myobj.GetProperty(name);
}
public class MyObject
{
private Dictionary<string, object> m_Properties = new Dictionary<string, object>();
public object GetProperty(string name)
{
return m_Properties[name];
}
public void SetProperty(string name, object value)
{
m_Properties[name] = value;
}
public object Prop1
{
get { return GetProperty("PropOne"); }
set { SetProperty("PropOne", value); }
}
public object Prop2
{
get { return GetProperty("PropTwo"); }
set { SetProperty("PropTwo", value); }
}
}
Option 2: Use reflection.
public GetMemberByName(MyObject myobj, string name)
{
return typeof(MyObject).GetProperty(name).GetValue(obj, null);
}
Option 3: Leave it the way it is.
This is a reasonable option because switch statements on string data types will be converted to a Dictionary lookup once the number case statements reaches a certain threshold. That threshold is 7 on the C# 3.0 compiler. So the lookup will be O(1) no matter how many case statements there are. It will not scan through each one.

You can use reflection to get a property dynamically at runtime. Here is a snippet from a little relection utility i wrote. This is written as an extension method which would easily allow you to get a property from your class instance
myInstance.GetProperty<string>("Title"); // Replace 'string' with the proper return value.
The code:
public static class ReflectionExtensions
{
private const BindingFlags DefaultFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
public static T GetProperty<T>(this object instance, string propertyName)
{
PropertyInfo property = GetPropertyInfo(instance, propertyName);
if (property == null)
{
var message = string.Format("The Type, '{0}' does not implement a '{1}' property", instance.GetType().AssemblyQualifiedName, propertyName);
throw new NotImplementedException(message);
}
return (T)property.GetValue(instance, null);
}
private static PropertyInfo GetPropertyInfo(object instance, string propertyName)
{
Type type = instance.GetType();
return type.GetProperty(propertyName, DefaultFlags);
}
}

Well, assuming that the Name matches the actual name of the property (unlike your example), this would probably be best handled through reflection.

You cant do it with an index, but you could use reflection.

You may want to try using something like this.
private static readonly Dictionary<Type, Dictionary<string, PropertyInfo>> _cache = new Dictionary<Type,Dictionary<string,PropertyInfo>>();
public static T GetProperty<T>(object obj, string name)
{
if (obj == null)
{
throw new ArgumentNullException("obj");
}
else if (name == null)
{
throw new ArgumentNullException("name");
}
lock (_cache)
{
var type = obj.GetType();
var props = default(Dictionary<string, PropertyInfo>);
if (!_cache.TryGetValue(type, out props))
{
props = new Dictionary<string, PropertyInfo>();
_cache.Add(type, props);
}
var prop = default(PropertyInfo);
if (!props.TryGetValue(name, out prop))
{
prop = type.GetProperty(name);
if (prop == null)
{
throw new MissingMemberException(name);
}
props.Add(name, prop);
}
return (T)prop.GetValue(obj, null);
}
}

Related

parse type hierarchy in assembly

Consider the following types in an assembly: BusinessPartnerList, BusinessPartner, PrivateData, CompanyData, AddressList, Address
Type BusinessPartnerList
{
BusinessPartner[]
}
Type BusinessPartner
{
PrivateData
CompanyData
AddressList
}
Type PrivateData
{
System.String FirstName
System.String SurName
}
Type PrivateData
{
System.String CompanName1
System.String CompanName2
}
Type AddressList
{
Address[]
}
I want to generic parse the type hierarchy, and represent them in a tree e.g. simple nodes
BusinessPartnerList[]
BusinessPartner
PrivateData
CompanyData
AddressList[]
Address
What is the best way to do this?
Unfortunately you didn't use proper C# syntax for your sample data. So I have to make some assumptions:
Type is actually class (or struct).
The contents of the types (BusinessPartner, PrivateData, CompanyData etc.) represent the types of some public properties.
To parse the type hierarchy you can use reflection. Find all public properties of a given type and return their types. Since you only want the types you can use a HashSet which will only contain distinct types:
public static HashSet<Type> GetPropertyTypes(Type type)
{
return new HashSet<Type>(type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(prop => prop.PropertyType));
}
However, it seems that you don't want to get information on arrays but rather on the type of the array elements. The same goes for lists. So if a type implements IEnumerable<T> you want to get information on the type T:
private static Type GetElementType(Type type)
{
Type enumerableType = type.GetInterfaces().FirstOrDefault(IsGenericEnumerable);
if (enumerableType != null)
{
Type[] genericArguments = enumerableType.GetGenericArguments();
return genericArguments[0];
}
// return 'object' for a non-generic IEnumerable
return typeof(IEnumerable).IsAssignableFrom(type) ? typeof(object) : type;
}
private static bool IsGenericEnumerable(Type type)
{
return type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}
Note that for the type System.String this will return char because string implements IEnumerable<char> (I will adress that later).
The .NET framework does not have a tree structure you can use out of the box. So you need to implement it yourself:
public class Node<T>
{
public Node(T value, IEnumerable<Node<T>> children)
{
Value = value;
Children = children.ToList();
}
public T Value
{
get;
private set;
}
public List<Node<T>> Children
{
get;
private set;
}
}
This is a very basic implementation just for demonstration purposes.
Instead of returning List<Type> the GetPropertyTypes method can now return Node<Type> and it should be renamed to CreateTypeNode:
public static Node<Type> CreateTypeNode(Type type)
{
var children = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(prop => GetElementType(prop.PropertyType))
.Select(CreateTypeNode);
return new Node<Type>(type, children);
}
This method uses recursion to create the full tree for the given type.
There is still a problem: What if type A references type B and vice versa? This would end up in an infinite recursive loop. And also: if a type has already been visited there is no need to do that again.
What we need is a cache for the types that have been visited. If a type is in the cache we use the information from the cache:
private static readonly Dictionary<Type, Node<Type>> _visitedTypes = new Dictionary<Type, Node<Type>>();
public static Node<Type> CreateTypeNode(Type type)
{
Node<Type> node;
if (_visitedTypes.TryGetValue(type, out node))
{
return node;
}
// add the key to the cache to prevent infinite recursion; the value will be set later
// if this type will be found again in a recursive call CreateTypeNode returns null
// (null will be filtered out then)
_visitedTypes.Add(type, null);
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var types = new HashSet<Type>(properties.Select(prop => GetElementType(prop.PropertyType)));
var children = types.Select(CreateTypeNode).Where(n => n != null);
node = new Node<Type>(type, children);
_visitedTypes[type] = node;
return node;
}
I you don't want the string type to be reported as char (because string implements IEnumerable<char>) you can just add a node for string to the cache before you call GetOrCreateTypeNode for the first time:
_visitedTypes.Add(typeof(string), new Node<Type>(typeof(string), new List<Node<Type>>()));
Then check the cache in the GetElementType method:
private static Type GetElementType(Type type)
{
if (_visitedTypes.ContainsKey(type))
{
return type;
}
...
}

Can properties be accessed as types?

Can I access object properties as a type?
I am using an API where I have to iterate through a collection of objects, and access the Text properties of two of these objects, either for reading or for writing. I currently have two methods for reading and writing as follows:
Result ReadTexts()
var attribs = SOME_CODE;
string first = "", second = "";
for(int i=1 ; i <= attribs.Count ; i++) {
if(attribs[i] IS_FIRST_ONE_NEEDED) {
first = attribs[i].Text;
} else if(attribs[i] IS_SECOND_ONE_NEEDED) {
second = attribs[i].Text;
}
}
return new Result(first, second);
}
void WriteTexts(string first, string second) {
var attribs = SOME_CODE;
for(int i=1 ; i <= attribs.Count ; i++) {
if(attribs[i] IS_FIRST_ONE_NEEDED) {
attribs[i].Text = first;
} else if(attribs[i] IS_SECOND_ONE_NEEDED) {
attribs[i].Text = second;
}
}
}
What I would prefer is using a more functional style which factors out the iteration and checking for the two objects in the collection into one method instead of repeating this code, as actually SOME_CODE as well as IS_FIRST_ONE_NEEDED and IS_SECOND_ONE_NEEDED are a bit longer in reality than in the above sample code. This one method would look like:
void AccessTexts(Action<StringProperty> first, Action<StringProperty> second) {
var attribs = SOME_CODE;
for(int i=1 ; i <= attribs.Count ; i++) {
if(attribs[i] IS_FIRST_ONE_NEEDED) {
first(attribs[i].Text);
} else if(attribs[i] IS_SECOND_ONE_NEEDED) {
second(attribs[i].Text);
}
}
}
and then call this with lambda expressions like
AccessTexts(( prop => prop = "abc"), ( prop => prop = "def"));
for writing, or
AccessTexts(( prop => firstString = prop), ( prop => secondString = prop));
for reading. This would be much shorter and avoid repeating a lot of code.
But I think this is not possible, as properties are not exposed as a real type in .net, but are just based on the availability of special methods - the getter and setter. Hence, there is no type StringProperty as I used it as type of the delegate parameter in the code sample of "what I would like to write".
Am I right, or is there some way to implement it the way I want?
You can create your own class that represents a property. As you've shown, a property is essentially just a get and set method, so that's all our class needs to represent.
As for how to create such a thing, one option is to have the type accept a getter and setter as delegates directly. Another option is to have it accept a PropertyInfo and an object which can then use reflection to implement the getter and setter methods. Finally, if you wanted to, you could even use an Expression to represent the property access, and then pull out the PropertyInfo from that.
So to start out with, the actual wrapper itself:
public class PropertyWrapper<T>
{
private Func<T> getter;
private Action<T> setter;
public PropertyWrapper(PropertyInfo property, object instance)
{
if (!typeof(T).IsAssignableFrom(property.PropertyType))
throw new ArgumentException("Property type doesn't match type supplied");
setter = value => property.SetValue(instance, value);
getter = () => (T)property.GetValue(instance);
}
public PropertyWrapper(Func<T> getter, Action<T> setter)
{
this.setter = setter;
this.getter = getter;
}
public T Get()
{
return getter();
}
public void Set(T value)
{
setter(value);
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
You can then use a helper such as this (it's extracted out of the other class so that there is generic type inference:
public class PropertyWrapper
{
public static PropertyWrapper<TProp> Create<TObject, TProp>(
TObject instance, Expression<Func<TObject, TProp>> expression)
{
var memberEx = expression.Body as MemberExpression;
var prop = memberEx.Member as PropertyInfo;
return new PropertyWrapper<TProp>(prop, instance);
}
}
Here is a simple example of constructing such an object using the two different syntaxes:
var list = new List<int>();
var prop1 = new PropertyWrapper<int>(
() => list.Capacity, cap => list.Capacity = cap);
var prop2 = PropertyWrapper.Create(list, l => l.Capacity);
prop2.Value = 42;
Console.WriteLine(list.Capacity); //prints 42
What you did is definitely workable. You are providing an accessor for the property in question to your function AccessTexts so that the function does not care how the access is done.
Normally, this would be solved using an interface implemented by the object being iterated over, or implemented by a wrapper class.
You can also use reflection or dynamic to do the access.
In any case you need a proxy between AccessTexts and the real objects.

Filtering on template list with property name as string

Hi I have to apply filter on generic class. The sample class is as follows
public class Sample<T>
{
List<T> sourceList = new List<T>();
public void applyFilter(string propertyName , EnumOperator operator , object value)
{
}
}
Here I want to implement filter using linq or dynamic linq but am not getting any positive direction to implement this functionality.
Please give me some positive direction so that I can implement this functionality.
Thanks.
I would recommend returning an filtered list instead of modifying the source, and also the string "operator" is a C# keyword, so the signature of the method could be:
public List<T> ApplyFilter(string propertyName, EnumOperator operatorType, object value)
{
....
}
where I assume that the EnumOperator is an enum with values like this:
public enum EnumOperator
{
Equal,
NotEqual,
Bigger,
Smaller
}
and that you have some way to check if for an operator a value passes or fails the test, something along the lines of:
public static class OperatorEvaluator
{
public static bool Evaluate(EnumOperator operatorType, object first, object second)
{
...
}
}
Given that, you can do something like:
public List<T> ApplyFilter(string propertyName , EnumOperator operatorType, object value)
{
PropertyInfo pi = typeof(T).GetProperty(propertyName);
List<T> result = sourceList.Where(item => {
var propValue = pi.GetValue(item, null);
return OperatorEvaluator.Evaluate(operatorType, propValue, value);
}).ToList();
return result;
}
That said, you can always use LINQ's methods to filter almost anything without resorting to reflection.
To query with dynamic expression (as string), you can use Dynamic LINQ by Scott Gu of Microsoft.
Samples
It supports following operations
1. Select
2. Where
3. OrderBy
4. Skip
5. Take
6. GroupBy
All above operations take string as parameter.
It also has small expression language (to build selectors/predicates/etc) which is very easy to use.
Example:
var query =
db.Customers.
Where("City = #0 and Orders.Count >= #1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
Here I give you a sample example how to implement filtering using LINQ on List<T> items..
public class clsCountry
{
public string _CountryCode;
public string _CountryName;
//
public clsCountry(string strCode, string strName)
{
this._CountryCode = strCode;
this._CountryName = strName;
}
//
public string CountryCode
{
get {return _CountryCode;}
set {_CountryCode = value;}
}
//
public string CountryName
{
get { return _CountryName; }
set { _CountryName = value; }
}
}
Now, lets create a list of objects based on class clsCountry and store them in a List<T> object.
List<clsCountry> lstCountry = new List<clsCountry>();
lstCountry.Add(new clsCountry("USA", "United States"));
lstCountry.Add(new clsCountry("UK", "United Kingdom"));
lstCountry.Add(new clsCountry("IND", "India"));
Next, we shall bind the List<T> object lstCountry to a DropDownList control named drpCountry as like as:
drpCountry.DataSource = lstCountry;
drpCountry.DataValueField = "CountryCode";
drpCountry.DataTextField = "CountryName";
drpCountry.DataBind();
Now, use LINQ to filter data from the lstCountry object and bind the filtered list to the dropdown control drpCountry.
var filteredCountries = from c in lstCountry
where c.CountryName.StartsWith("U")
select c;
drpCountry.DataSource = filteredCountries;
drpCountry.DataValueField = "CountryCode";
drpCountry.DataTextField = "CountryName";
drpCountry.DataBind();
Now the dropdown control will have only 2 items
United States
United Kingdom
Now apply those techniques on your case..
You can use Reflection for retrieving the property value and you can use a simple switch statement upon the operator to perform the filtering:
public IEnumerable<T> ApplyFilter(string propertyName, EnumOperator op, object value)
{
foreach (T item in sourceList)
{
object propertyValue = GetPropertyValue(item, propertyName);
if (ApplyOperator(item, propertyValue, op, value)
{
yield return item;
}
}
}
private object GetPropertyValue(object item, string propertyName)
{
PropertyInfo property = item.GetType().GetProperty(propertyName);
//TODO handle null
return property.GetValue();
}
private bool ApplyOperator(object propertyValue, EnumOperator op, object value)
{
switch (op)
{
case EnumOperator.Equals:
return propertyValue.Equals(value);
//TODO other operators
default:
throw new UnsupportedEnumException(op);
}
}
(An optimization would be to look up the PropertyInfo once outside of the loop.)

Can an extension method be added to a class property to get the value of an attribute associated with the property?

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();

Is there a way of making C# binding work statically?

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)

Categories