Create Expression that accesses a property - c#

I have a following class:
internal class Sensors
{
public JsonSensor<double> IOPcwFlSpr { get; set; } = new JsonSensor<double>();
}
internal class JsonSensor<TType> : IJsonSensor
{
public TType Value { get; set; }
}
I want to build an expression that retrieves that property.
private static readonly List < PropertyInfo > Properties;
static SensorFactory() {
Properties = typeof(Json.Sensors).GetProperties().ToList();
}
public void Test(Json.Sensors jsonUpdate) {
foreach(var property in Properties) {
var getterMethodInfo = property.GetGetMethod();
var parameterExpression = Expression.Parameter(jsonUpdate.GetType(), "x");
var callExpression = Expression.Call(parameterExpression, getterMethodInfo);
var lambda = Expression.Lambda < Func < JsonSensor < double >>> (callExpression);
var r = lambda.Compile().Invoke();
}
}
This throws:
System.InvalidOperationException : variable 'x' of type 'Sensors'
referenced from scope '', but it is not defined
Which makes sense, because I never assigned 'x' with an actual object. How do I add the 'parameter object'?

The key when using expression trees like this is to compile it once using a parameter (ParameterExpression), creating a Func<Foo,Bar> that takes your input (Foo) and returns whatever you wanted (Bar). Then reuse that compiled delegate many times, with different objects.
I can't see exactly what you're trying to do, but I'm guessing it would be something like:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Json
{
static class P
{
static void Main()
{
var obj = new Sensors { IOPcwFlSpr = { Value = 42.5 }, Whatever = { Value = 9 } };
foreach(var pair in SomeUtil.GetSensors(obj))
{
Console.WriteLine($"{pair.Name}: {pair.Value}");
}
}
}
public class Sensors
{
public JsonSensor<double> IOPcwFlSpr { get; set; } = new JsonSensor<double>();
public JsonSensor<int> Whatever { get; set; } = new JsonSensor<int>();
}
public interface IJsonSensor
{
public string Value { get; }
}
public class JsonSensor<TType> : IJsonSensor
{
public TType Value { get; set; }
string IJsonSensor.Value => Convert.ToString(Value);
}
public static class SomeUtil
{
private static readonly (string name, Func<Sensors, IJsonSensor> accessor)[] s_accessors
= Array.ConvertAll(
typeof(Sensors).GetProperties(BindingFlags.Instance | BindingFlags.Public),
prop => (prop.Name, Compile(prop)));
public static IEnumerable<(string Name, string Value)> GetSensors(Sensors obj)
{
foreach (var acc in s_accessors)
yield return (acc.name, acc.accessor(obj).Value);
}
private static Func<Sensors, IJsonSensor> Compile(PropertyInfo property)
{
var parameterExpression = Expression.Parameter(typeof(Json.Sensors), "x");
Expression body = Expression.Property(parameterExpression, property);
body = Expression.Convert(body, typeof(IJsonSensor));
var lambda = Expression.Lambda<Func<Json.Sensors, IJsonSensor>>(body, parameterExpression);
return lambda.Compile();
}
}
}

Related

Using LINQ to select EF properties in DBSet with specific Attributes

Is there a way to perform a LINQ query on Entity Framework DBSets and only return the properties that have a specific custom attribute?
My goal is to perform a query and return only the properties/columns that I need for an export.
I also want to make this an extension for IEnumerable as I have many separate EF Classes that will use this export attribute.
This is how I am visualizing it:
public class Person
{
[Export]
public string FirstName { get; set; }
[Export]
public string LastName { get; set; }
[Export]
public string Address { get; set; }
[NeverExport]
public string SocialSecurityNumber { get; set; }
}
public void main()
{
var people = PersonRepository.GetAll();
var exportResults = people.GetByAttribute(ExportAttribute);
{
public static IEnumerable<object> GetByAttribute(this IEnumerable<object> list, Attribute attribute)
{
return list
.Select(x =>
// Select properties with { attribute } (ie. [Export])
);
}
I've made a very basic example for your problem. In short, you want to get all Properties, where a specific Attribute is present. You can achive this via reflection. First, you want all properties of a specific type, then only the properties, where a specific attribute is present.
Here is my example code:
using System;
using System.Linq;
using System.Reflection;
namespace Sandbox
{
public class Program
{
public static void Main(string[] args)
{
var attrs = typeof(User).GetProperties().Where(x => x.GetCustomAttributes().Any(y => y.GetType() == typeof(Custom)));
var users = new User[]
{
new User() { ID = 1, Name = "John", Lastname = "Doe" },
new User() { ID = 2, Name = "Jane", Lastname = "Doe" }
};
foreach(var u in users)
{
foreach(var attr in attrs)
{
Console.WriteLine(typeof(User).GetProperty(attr.Name).GetValue(u, null));
}
}
}
}
public class User
{
public string Name { get; set; }
[Custom]
public int ID { get; set; }
[Custom]
public string Lastname { get; set; }
}
public class Custom : System.Attribute
{
}
}
The following code projects any IQueryable to IQueryable<ExpandoObject> and you can use it for exporting data. Additionally code caches projection expression for reusing later in application.
Usage is simple:
var exportResult = anyQuery.ProjectForExport().ToList();
And implementation:
[AttributeUsage(AttributeTargets.Property)]
public class ExportAttribute : Attribute
{
}
public static class ExportTools
{
private static readonly ConstructorInfo _expandoObjectConstructor =
typeof(ExpandoObject).GetConstructor(Type.EmptyTypes) ?? throw new InvalidOperationException();
private static readonly MethodInfo _expandoAddMethodInfo = typeof(IDictionary<string, object>).GetTypeInfo()
.GetRuntimeMethods()
.Single(mi => mi.Name == nameof(IDictionary<string, object>.Add) && mi.GetParameters().Length == 2);
public static class ProjectionCache<T>
{
public static Expression<Func<T, ExpandoObject>> ProjectionExpression { get; } = BuildProjection();
private static Expression<Func<T, ExpandoObject>> BuildProjection()
{
var param = Expression.Parameter(typeof(T), "e");
var properties = typeof(T).GetProperties()
.Where(p => p.GetCustomAttributes().Any(a => a is ExportAttribute)).ToList();
if (properties.Count == 0)
throw new InvalidOperationException($"Type '{typeof(T).Name}' has no defined Export properties.");
var expr = (Expression)Expression.ListInit(
Expression.New(_expandoObjectConstructor),
properties.Select(p =>
{
var readerExpr = Expression.MakeMemberAccess(param, p);
return Expression.ElementInit(_expandoAddMethodInfo, Expression.Constant(p.Name), readerExpr);
}));
var lambda = Expression.Lambda<Func<T, ExpandoObject>>(expr, param);
return lambda;
}
}
public static IQueryable<ExpandoObject> ProjectForExport<T>(this IQueryable<T> query)
{
return query.Select(ProjectionCache<T>.ProjectionExpression);
}
}

C# LINQ, dynamic grouping by [Key] attributes

Consider the following classes:
public class Potato
{
[Key]
public string Farm { get; set; }
[Key]
public int Size { get; set; }
public string Trademark { get; set; }
}
public class Haybell
{
[Key]
public string color { get; set; }
public int StrawCount { get; set; }
}
public class Frog
{
[Key]
public bool IsAlive { get; set; }
[Key]
public bool IsVirulent { get; set; }
public byte LimbCount { get; set; } = 4;
public ConsoleColor Color { get; set; }
}
Each class has properties with [Key] attribute. Is it possible to dynamically group an IEnumerable of any of these classes by their respective [Key] attributes?
I would go for adding extension methods for each your types, like
Option 1:
static class Extensions
{
public static IEnumerable<IGrouping<Tuple<string, int>, Potato>>
GroupByPrimaryKey(this IEnumerable<Potato> e)
{
return e.GroupBy(p => Tuple.Create(p.Farm, p.Size));
}
public static IEnumerable<IGrouping<Tuple<bool, bool>, Frog>>
GroupByPrimaryKey(this IEnumerable<Frog> e)
{
return e.GroupBy(p => Tuple.Create(p.IsAlive, p.IsVirulent));
}
}
If there are lots of types, you may generate the code using t4.
Usage: .GroupByPrimaryKey().
Option 2:
A simpler variation:
static class Extensions
{
public static Tuple<string, int> GetPrimaryKey(this Potato p)
{
return Tuple.Create(p.Farm, p.Size);
}
public static Tuple<bool, bool> GetPrimaryKey(this Frog p)
{
return Tuple.Create(p.IsAlive, p.IsVirulent);
}
}
Usage: .GroupBy(p => p.GetPrimaryKey()).
Option 3:
A solution with reflection is possible, but will be slow. Sketch (far from production-ready!)
class CombinedKey : IEquatable<CombinedKey>
{
object[] _keys;
CombinedKey(object[] keys)
{
_keys = keys;
}
public bool Equals(CombinedKey other)
{
return _keys.SequenceEqual(other._keys);
}
public override bool Equals(object obj)
{
return obj is CombinedKey && Equals((CombinedKey)obj);
}
public override int GetHashCode()
{
return 0;
}
public static CombinedKey GetKey<T>(T instance)
{
return new CombinedKey(GetKeyAttributes(typeof(T)).Select(p => p.GetValue(instance, null)).ToArray());
}
private static PropertyInfo[] GetKeyAttributes(Type type)
{
// you definitely want to cache this
return type.GetProperties()
.Where(p => Attribute.GetCustomAttribute(p, typeof(KeyAttribute)) != null)
.ToArray();
}
}
Usage: GroupBy(p => CombinedKey.GetKey(p))
The challenge here is that you need to build an anonymous type in order to have a GroupBy Expression that can translate to SQL or any other LINQ provider.
I'm not sure that you can do that using reflection (not without some really complex code to create an anonymous type at runtime). But you could create the grouping expression if you were willing to provide an example of the anonymous type as the seed.
public static Expression<Func<TSource, TAnon>> GetAnonymous<TSource,TAnon>(TSource dummy, TAnon example)
{
var ctor = typeof(TAnon).GetConstructors().First();
var paramExpr = Expression.Parameter(typeof(TSource));
return Expression.Lambda<Func<TSource, TAnon>>
(
Expression.New
(
ctor,
ctor.GetParameters().Select
(
(x, i) => Expression.Convert
(
Expression.Property(paramExpr, x.Name), // fetch same named property
x.ParameterType
)
)
), paramExpr);
}
And here's how you would use it (Note: the dummy anonymous type passed to the method is there in order to make the anonymous type a compile-time Type, the method doesn't care what the values are that you pass in for it.) :
static void Main()
{
var groupByExpression = GetAnonymous(new Frog(), new {IsAlive = true, IsVirulent = true});
Console.WriteLine(groupByExpression);
var frogs = new []{ new Frog{ IsAlive = true, IsVirulent = false}, new Frog{ IsAlive = false, IsVirulent = true}, new Frog{ IsAlive = true, IsVirulent = true}};
var grouped = frogs.AsQueryable().GroupBy(groupByExpression);
foreach (var group in grouped)
{
Console.WriteLine(group.Key);
}
}
Which produces:
Param_0 => new <>f__AnonymousType0`2(Convert(Param_0.IsAlive, Boolean), Convert(Param_0.IsVirulent, Boolean))
{ IsAlive = True, IsVirulent = False }
{ IsAlive = False, IsVirulent = True }
{ IsAlive = True, IsVirulent = True }
Somebody had posted a valid answer and removed it later for some reason. Here it is:
Combined key class:
class CombinedKey<T> : IEquatable<CombinedKey<T>>
{
readonly object[] _keys;
public bool Equals(CombinedKey<T> other)
{
return _keys.SequenceEqual(other._keys);
}
public override bool Equals(object obj)
{
return obj is CombinedKey<T> key && Equals(key);
}
public override int GetHashCode()
{
int hash = _keys.Length;
foreach (object o in _keys)
{
if (o != null)
{
hash = hash * 13 + o.GetHashCode();
}
}
return hash;
}
readonly Lazy<Func<T, object[]>> lambdaFunc = new Lazy<Func<T, object[]>>(() =>
{
Type type = typeof(T);
var paramExpr = Expression.Parameter(type);
var arrayExpr = Expression.NewArrayInit(
typeof(object),
type.GetProperties()
.Where(p => (Attribute.GetCustomAttribute(p, typeof(KeyAttribute)) != null))
.Select(p => Expression.Convert(Expression.Property(paramExpr, p), typeof(object)))
.ToArray()
);
return Expression.Lambda<Func<T, object[]>>(arrayExpr, paramExpr).Compile();
}, System.Threading.LazyThreadSafetyMode.PublicationOnly);
public CombinedKey(T instance)
{
_keys = lambdaFunc.Value(instance);
}
}
Caller function and the actual usage:
public static class MyClassWithLogic
{
//Caller to CombinedKey class
private static CombinedKey<Q> NewCombinedKey<Q>(Q instance)
{
return new CombinedKey<Q>(instance);
}
//Extension method for IEnumerables
public static IEnumerable<T> DistinctByPrimaryKey<T>(this IEnumerable<T> entries) where T : class
{
return entries.AsQueryable().GroupBy(NewCombinedKey)
.Select(r => r.First());
}
}
Yes, it is relatively slow, so if it is a problem, then Klaus Gütter's solutions are the way to go.

Func list for storing function pointer and parameter value

I want to store a list of functions with their parameter value and later when I am done adding function to the list. I want to execute all in the order I have added.
For example, I want to use func instead of action and don't want to create anonymous functions while calling parametered function:
Dynamic function list class to hold a function list and execute it later.
class DynamicFunctionList
{
public List<Action> DynamicList = new List<Action>();
public void Execute()
{
foreach (var obj in DynamicList)
{
obj();
}
}
}
some class with functions
public class SomeClass
{
public void PrintHello()
{
Console.Write("Hello");
}
public void PrintBye()
{
Console.Write("Print Bye");
}
public int GetPrinterValue()
{
return 2;
}
public int Add(int a, int b)
{
return (a + b);
}
}
And this is how you will use it
public static void MainClass()
{
var first = 0;
var second = 0;
var dfList = new DynamicFunctionList();
var sClass = new SomeClass();
dfList.DynamicList.Add(() => first = sClass.GetPrinterValue()); // problem line
dfList.DynamicList.Add(sClass.PrintBye);
dfList.DynamicList.Add(sClass.PrintHello);
dfList.DynamicList.Add(() => second = sClass.Add(2, 3)); // problem
dfList.Execute();
}
I do something like that:
public void main()
{
List<MethodInvoker> methods = new List<MethodInvoker>();
methods.Add(new MethodInvoker(SomeMethod));
foreach (var method in methods)
{
method.Invoke();
}
}
public void SomeMethod()
{
//... do something
}
EDIT 1:
You can use MethodBase.Invoke from System.Reflection namespace (more infos: https://msdn.microsoft.com/en-us/library/a89hcwhh%28v=vs.110%29.aspx)
You can do something like that:
public class DynamicMethod
{
public string ClassName { get; set; }
public string MethodName { get; set; }
public object[] Parameters { get; set; }
public static object InvokeMethod(DynamicMethod methodInfo)
{
var magicType = Type.GetType(methodInfo.ClassName);
var magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
var magicInstance = magicConstructor.Invoke(new object[] {});
var magicMethod = magicType.GetMethod(methodInfo.MethodName);
return magicMethod.Invoke(magicInstance, methodInfo.Parameters);
}
}
public class Example
{
public static void main()
{
var d1 = new DynamicMethod
{
ClassName = "SomeClass",
MethodName = "Add",
Parameters = new object[] { 1, 2 }
};
var returnedValue = DynamicMethod.InvokeMethod(d1);
Console.WriteLine(returnedValue.ToString());
}
Also you can add more information to this class, like some way to store the returned type to do the properly cast.

Get Name and Value of a property of a POCO object using an expression

I'm looking for a way to get the name and value of a proptery in a POCO object. I've tried many solutions but can't seem to get them to work. I really liked this older solution but it causes a null ref error.
Here's kind of what I'm trying to do:
public class POCO
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Description { get; set; }
}
public class POCOValidationResult
{
public bool IsValid { get; set; }
public string Error { get; set; }
}
public abstract class Validator<T> where T : class
{
public T Entity { get; set; }
public abstract POCOValidationResult Validate();
protected POCOValidationResult ValidateStringPropertyToLengthOf(Expression<Func<T, object>> expression, int maxLength)
{
var propertyName = getPropertyName(expression);
var propertyValue = getPropertyValue(expression);
if (propertyValue.Length > maxLength)
{
return new POCOValidationResult()
{
Error = string.Format("{0} value is too long. Must be less or equal to {1}", propertyName, maxLength.ToString())
};
}
return new POCOValidationResult() { IsValid = true };
}
internal string getPropertyName(Expression<Func<T, object>> expression)
{
var memberExpersion = (MemberExpression)expression.Body;
return memberExpersion.Member.Name;
}
internal string getPropertyValue<R>(Expression<Func<T, R>> expression)
{
//struggling to get this to work
var me = (MemberExpression)expression.Body; // (MemberExpression)((MemberExpression)expression.Body).Expression;
var ce = (ConstantExpression)me.Expression; // Error here!
var fieldInfo = ce.Value.GetType().GetField(me.Member.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var value = fieldInfo.GetValue(ce.Value);
}
}
public class POCOValidator : Validator<POCO>
{
public override POCOValidationResult Validate()
{
var surnameValidationResult = ValidateStringPropertyToLengthOf(p => p.Surname, 10);
if (!surnameValidationResult.IsValid)
return surnameValidationResult;
//var descriptionValidationResult = ValidateStringPropertyToLengthOf(p => p.Description, 100);
//if (!descriptionValidationResult.IsValid)
// return descriptionValidationResult;
//var nameValidationResult = ValidateStringPropertyToLengthOf(p => p.Name, 15);
//if (!nameValidationResult.IsValid)
// return nameValidationResult;
return new POCOValidationResult() { IsValid = true };
}
}
public class WorkerBee
{
public void ImDoingWorkReally()
{
var pocoVallidation = new POCOValidator()
{
Entity = new POCO()
{
ID = 1,
Name = "James",
Surname = "Dean",
Description = "I'm not 007!"
}
};
var vallidationResult = pocoVallidation.Validate();
if (!vallidationResult.IsValid)
{
return;
}
//continue to do work...
}
}
class Program
{
static void Main(string[] args)
{
var workerBee = new WorkerBee();
workerBee.ImDoingWorkReally();
}
}
So as you can see, I'm trying to get the Property's name and value [by using an Expression (p => p.Surname) as a parameter in the method ValidateStringPropertyToLengthOf(...)]. The problem is that I'm getting a null ref error in getPropertyValue(Expression<Func<T, object>> expression) when it calls var ce = (ConstantExpression)me.Expression;
So does anyone have ideas on how to get this to work?
Thanks for taking the time to look into this. I really appreciate it and hope that my question also is helpful for others as I think this can be rather useful if I can get this to work.
EDIT: I've made the change as mentioned below in the comments and still getting the error "Unable to cast object of type 'System.Linq.Expressions.TypedParameterExpression' to type 'System.Linq.Expressions.ConstantExpression" when I run my unit test.
I worked out a solution (unfortunately the comments were not helpful). Here's the code that works:
public class POCO
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Description { get; set; }
}
public class POCOValidationResult
{
public bool IsValid { get; set; }
public string Error { get; set; }
}
public abstract class Validator<T> where T : class
{
public T Entity { get; set; }
public abstract POCOValidationResult Validate();
protected POCOValidationResult ValidateStringPropertyToLengthOf(Expression<Func<T, object>> expression, int maxLength)
{
var propertyName = getPropertyName(expression);
var propertyValue = getPropertyValue(expression);
if (propertyValue.Length > maxLength)
{
return new POCOValidationResult()
{
Error = string.Format("{0} value is too long. Must be less or equal to {1}", propertyName, maxLength.ToString())
};
}
return new POCOValidationResult() { IsValid = true };
}
internal string getPropertyName(Expression<Func<T, object>> expression)
{
var memberExpersion = (MemberExpression)expression.Body;
return memberExpersion.Member.Name;
}
internal string getPropertyValue(Expression<Func<T, object>> expression)
{
var memberExpression = expression.Body as MemberExpression;
var propertyInfo = memberExpression.Member as PropertyInfo;
return propertyInfo.GetValue(Entity, null).ToString();
}
}
public class POCOValidator : Validator<POCO>
{
public override POCOValidationResult Validate()
{
var surnameValidationResult = ValidateStringPropertyToLengthOf(p => p.Surname, 10);
if (!surnameValidationResult.IsValid)
return surnameValidationResult;
var descriptionValidationResult = ValidateStringPropertyToLengthOf(p => p.Description, 100);
if (!descriptionValidationResult.IsValid)
return descriptionValidationResult;
var nameValidationResult = ValidateStringPropertyToLengthOf(p => p.Name, 15);
if (!nameValidationResult.IsValid)
return nameValidationResult;
return new POCOValidationResult() { IsValid = true };
}
}
public class WorkerBee
{
public void ImDoingWorkReally()
{
var pocoVallidation = new POCOValidator()
{
Entity = new POCO()
{
ID = 1,
Name = "James",
Surname = "Dean",
Description = "I'm not 007!"
}
};
var vallidationResult = pocoVallidation.Validate();
if (!vallidationResult.IsValid)
{
return;
}
//continue to do work...
}
}
class Program
{
static void Main(string[] args)
{
var workerBee = new WorkerBee();
workerBee.ImDoingWorkReally();
}
}
Note the change for getPropertyValue:
internal string getPropertyValue(Expression<Func<T, object>> expression)
{
var memberExpression = expression.Body as MemberExpression;
var propertyInfo = memberExpression.Member as PropertyInfo;
return propertyInfo.GetValue(Entity, null).ToString();
}
I noticed that MaudDib's getPropertyValue method only works for properties directly on the object. e.g. it will work for myObj.Value, but not for myObj.Something.Value. The following works for both. (I don't know if there's a better way, though).
Usage: var myValue = GetPropertyValue(myObj, o => o.Something.Value);
public static object GetPropertyValue<T>(T obj, Expression<Func<T, object>> expression)
{
var members = new CompositeExpressionVisitor().GetMembers(expression);
object currentVal = obj;
foreach (var part in members)
{
currentVal = GetPropertyValue(currentVal, part);
}
return currentVal;
}
private static object GetPropertyValue(object obj, MemberInfo member)
{
var propertyInfo = (PropertyInfo)member;
return propertyInfo.GetValue(obj, null);
}
private class CompositeExpressionVisitor : ExpressionVisitor
{
private readonly List<MemberInfo> _members = new List<MemberInfo>();
protected override Expression VisitMember(MemberExpression node)
{
_members.Add(node.Member);
return base.VisitMember(node);
}
public IReadOnlyCollection<MemberInfo> GetMembers(Expression e)
{
Visit(e is LambdaExpression expression ? expression.Body : e);
_members.Reverse();
return _members;
}
}
And, if you want the full path of the expression, e.g. you don't just want the leaf... you can do this:
Usage: var myValue = NameOf(() => myObj.Something.Value);
Returns: myObj.Something.Value
Or: var myValue = NameOf(() => myObj.Something.Value, 1);
Returns: Something.Value
public static string NameOf(Expression<Func<object>> expression, int startIndex = 0)
{
return new CompositeExpressionVisitor().GetPath(expression, startIndex);
}
private class CompositeExpressionVisitor : ExpressionVisitor
{
private readonly List<string> _parts = new List<string>();
protected override Expression VisitMember(MemberExpression node)
{
_parts.Add(node.Member.Name);
return base.VisitMember(node);
}
protected override Expression VisitParameter(ParameterExpression node)
{
_parts.Add(node.Name);
return base.VisitParameter(node);
}
public string GetPath(Expression e, int startIndex = 0)
{
Visit(e is LambdaExpression expression ? expression.Body : e);
_parts.Reverse();
return string.Join(".", _parts.Skip(startIndex));
}
}

Accessing object properties from string representations

In actionscript an object's property can be accesses in this way:
object["propertyname"]
Is something like this possible in c#, without using reflection?
No, you have to use reflection.
If could at most create an helper extension method like in this example:
using System;
static class Utils {
public static T GetProperty<T>(this object obj, string name) {
var property = obj.GetType().GetProperty(name);
if (null == property || !property.CanRead) {
throw new ArgumentException("Invalid property name");
}
return (T)property.GetGetMethod().Invoke(obj, new object[] { });
}
}
class X {
public string A { get; set; }
public int B { get; set; }
}
class Program {
static void Main(string[] args) {
X x = new X() { A = "test", B = 3 };
string a = x.GetProperty<string>("A");
int b = x.GetProperty<int>("B");
}
}
This is not good, however.
First because you are turning compile-time errors in runtime errors.
Second, the performance hit from reflection is unjustified in this case.
I think that the best advice here is that you should not try to program in C# as if it was ActionScript.
You can define indexer in your class:
public class IndexerTest
{
private Dicionary<string, string> keyValues = new ...
public string this[string key]
{
get { return keyValues[key]; }
set { keyValues[key] = value; }
}
}
And use it like this:
string property = indexerTest["propertyName"];

Categories