Is it possible to input an object and a second parameter to a method so that the second parameter can be used (without using strings and reflection) to get the a property of the object and use the property to both read and write the value?
I've written two methods below that I can use but each one has drawbacks. The first DoStuff is typesafe ("good") but it needs three parameters ("bad"). The second needs two parameters (optimal), but it is not typesafe ("bad") as it relies on a string to specify the property. Maybe there is some solution using Expression that I have not thought of?
Background: The usecase is that I want to be able to "extend" the value of any object (in my case I have lists of objects from several object reposites and these objects may have serveral properties containing userids as strings. another repository conatins the users and I want add info about the user to the strings in the previous repositories)
public class Foo
{
public string Bar {get; set;}
}
void Main()
{
var x = new Foo { Bar = "hello" };
Console.WriteLine(x.Bar); // prints "hello"
// the second paramter (Func<..>) gets the value, the third parameter Action<...>) sets the value
DoStuff(x, y => y.Bar, (z, val) => z.Bar = val);
Console.WriteLine(x.Bar); // prints "hello goodbye"
// just one parameter to get the property, but I would like this to be more type safe, preferably a Func
DoStuff2(x, nameof(x.Bar));
Console.WriteLine(x.Bar); // prints "hello goodbye again"
}
public void DoStuff<T>(
T obj,
Func<T, string> getProp,
Action<T, string> setProp)
{
var x = getProp(obj);
setProp(obj, x + " goodbye");
}
public void DoStuff2<T>(
T obj,
string propName)
{
var propInfo = typeof(T).GetProperty(propName);
var currValue = propInfo.GetValue(obj) as string;
propInfo.SetValue(obj, currValue + " again");
}
Well i did something like that awhile ago. here is an example:
public void SetValue<T, TP>(T obj, Expression<Func<T, TP>> action, TP value) where T : class
{
var member = action.Body is UnaryExpression
? ((MemberExpression)((UnaryExpression)action.Body).Operand)
: (action.Body is MethodCallExpression
? ((MemberExpression)((MethodCallExpression)action.Body).Object)
: (MemberExpression)action.Body);
var key = member?.Member.Name;
typeof(T).GetProperty(key).SetValue(obj, value);
}
You call it like this.
SetValue<User>(x=> x.UserName, "Admin");
Related
I am new to C# and I am trying to create a method that accept generic parameter type like in Javascript.
Let says I have a List of User objects with name and id properties.
In Javascript , to search through the list using property value will be as simple as:
class User{
constructor(name, id){
this.name = name;
this.id = id;
}
}
let users = [
new User("John",1),
new User("Deer", 2),
new User("Bruce", 3),
]
function findArr(arr, propertyName, propertyValue){
for(let a of arr)
if(a[propertyName] === propertyValue)
return a;
return null;
}
console.log(findArr(users, "name", "Deer"))
console.log(findArr(users, "id", 3))
Then, I try to recreate this in C#:
using System;
using System.Collections.Generic;
using System.Linq;
public class User{
public string name {get; set;}
public int id {get; set;}
}
public class HelloWorld
{
public static void Main(string[] args)
{
List<User> Users = new List<User>{
new User{name="John", id=1},
new User{name="Deer", id=2},
new User{name="Bruce", id=3}
};
int propertyValue = 2;
var u = FindList<User, int>(Users, "id", ref propertyValue);
Console.WriteLine(u.name + " " + u.id);
}
public static T FindList<T, K>(List<T> obj, string propertyName, ref K propertyValue){
return (T)obj.FirstOrDefault(o=>
(K)o.GetType().GetProperty(propertyName).GetValue(o, null)
==
propertyValue
);
}
}
But this will throw exception: Cannot use ref, out, or in parameter 'propertyValue' inside an anonymous method, lambda expression, query expression, or local function.
Why is this exception thrown?
How do I make this work?
As the error message states, you cannot use the ref or out keywords in an anonymous function. This is by design, as detailed in this answer.
The good news is, you do not need to use ref at all. You can achieve what you want simply by passing the property value as a normal parameter, like so:
public static T FindList<T, K>(List<T> obj, string propertyName, K propertyValue){
return (T)obj.FirstOrDefault(o=>
EqualityComparer<K>.Default.Equals((K)o.GetType().GetProperty(propertyName).GetValue(o, null) , propertyValue));
}
Note that the equality check with == operator won't work for unconstrained generic type in general, so we use the EqualityComparer method instead.
Javascript is a weakly typed language, every object is essentially just a dictionary.
If you ever find yourself accessing properties by name in C#, you're probably doing something "wrong".
Rather than using reflection, you could pass in a function to access the property;
public static T FindList<T, V>(List<T> obj, Func<T,V> propertyAccess, V propertyValue){
return obj.FirstOrDefault(o => propertyAccess(o) == propertyValue);
}
var u = FindList<User, int>(Users, u => u.id, propertyValue);
However, I don't think this method really adds anything to your C# code. You'd be better off just writing the straight forward solution, without complicating anything with your own "helper" method;
var u = Users.FirstOrDefault(u => u.id == propertyValue);
It's not the same as the javascript code you are familiar with. But you're writing in C# now. If you want to work with other C# programmers, you will need to change the way you think about programming problems.
I have list of dynamic objects where I want to query by custom property. In other words, it would look like this if I wasn't going for reflection:
IEnumerable<User> FilterUsers(IEnumerable<User> users, string selectedValue)
{
users.Where(user => user.Name == selectedValue);
}
So far I've come up with the following implementation that works if users is typed:
IEnumerable<User> FilterUsers(IEnumerable<User> users, string selectedField, string selectedValue)
{
LabelTarget returnTarget = Expression.Label(typeof(bool));
ParameterExpression userParameter = Expression.Parameter(typeof(User));
MemberExpression userSelectedField = Expression.Property(userParameter, selectedField);
Expression test = Expression.Equal(userSelectedField, Expression.Constant(selectedValue));
Expression iftrue = Expression.Return(returnTarget, Expression.Constant(true));
Expression iffalse = Expression.Return(returnTarget, Expression.Constant(false));
var ex = Expression.Block(
Expression.IfThenElse(test, iftrue, iffalse),
Expression.Label(returnTarget, Expression.Constant(false)));
var whereClause = Expression.Lambda<Func<User, bool>>(
ex,
new ParameterExpression[] { userParameter }
).Compile();
return users.Where(user => whereClause(user));
}
What I am really trying to do is to make users dynamic object:
IEnumerable<dynamic> FilterUsers(IEnumerable<dynamic> users, string selectedField, string selectedValue) {
// ...
ParameterExpression userParameter = Expression.Parameter(typeof(object)); // ???
MemberExpression userSelectedField = Expression.Property(userParameter, selectedField); // throws
// ...
}
This throws the following exception: Instance property 'Name' is not defined for type 'System.Object' (Parameter 'propertyName'). What am I missing?
Alternatively, how can I use Dictionary<string, object>?
Using dynamic here doesn't get you much: you'd be better off using generics if you can:
IEnumerable<T> FilterUsers<T>(IEnumerable<T> users, string selectedField, string selectedValue)
{
var userParameter = Expression.Parameter(typeof(T));
var userSelectedField = Expression.Property(userParameter, selectedField);
// etc...
}
If you do need to use dynamic, then you'll need to get the runtime type of each user, using .GetType(). However bear in mind that there's nothing stopping someone from passing in an IEnumerable containing lots of different types of object, and they don't all have to have a property called selectedField!
Or, they might pass in lots of different types of object, each of one has a property called selectedField, but they're distinct properties (e.g. class A { public string Foo { get; set; } } and class B { public string Foo { get; set; } } -- those two Foo properties are distinct).
So you'll have to call .GetType() on each one of them, which means you won't be able to get the performance benefits of using compiled expressions.
If you can guarantee that all elements have the same type, you can do something like:
private static IEnumerable<dynamic> FilterCollection(IEnumerable<dynamic> collection, string property, string value)
{
if (!collection.Any()) return collection;
var collectionItemType = collection.First().GetType();
var userParameter = Expression.Parameter(typeof(object));
var convertedUser = Expression.Convert(userParameter, collectionItemType);
var userSelectedField = Expression.Property(convertedUser, selectedField);
...
}
Beware however that you're enumerating users twice, which is probably a bad thing. You might do better to get the IEnumerator yourself and work with it explicitly.
As #canton7 said you should be using a generic method. I also see in your question you specified you're looking for properties, why not use regular old reflection?
public static IEnumerable<T> FilterItems<T>(IEnumerable<T> items, string property, string value)
{
var prop = typeof(T).GetProperties().First(p => p.Name == property);
return items.Where(i => prop.GetValue(i).ToString().Contains(value));
}
Of course that code should be enhanced to handle different errors....
I want to implement this method from MOQ. (Little out of my depth here)
ISetup<T> Setup(Expression<Action<T>> expression);
public class Foo {
public string Bar { get; set; }
public int Baz { get; set; }
}
public class MyCoolClass
{
public ? Evaluate<Expression<Action>>(expression);
//I want to be able to access and test the value of Foo.Bar (see below)
}
public class ClientOfMyClass
{
public void UseTheMethod()
{
MyCoolClass myCool = new MyCoolClass();
bool result = myCool.Evaluate<Foo>(f => f.Bar);
}
}
Basically, I am trying to write a method that will allow the caller to specify a property on an object with an expression, and allow me to test the value of that property and do something with it.
You want to use an Expression<Func<>> parameter, and check that it contains a Body, and a Member of type PropertyInfo, and use GetValue() passing your object in.
public static void Evaluate<TObj,TProp>(
this TObj obj,
Expression<Func<TObj, TProp>> expr)
{
var prop = (expr.Body as MemberExpression)?.Member as PropertyInfo;
var val = prop?.GetValue(obj);
if (val != null) {
//Do something
}
}
Note that the above code requires the passed in lambda to point to a Property. If you want to handle Fields as well as Methods, they will come in as different types of Expressions, and you'll want to handle handle them slightly differently. For more context and usage, here's a Fiddle.
Edit: Updated to work with other property types.
I want to write a generic function that takes an object and a series of properties of this object. Inside the function I would like to select a new anonymous object that is simply just those properties of the passed in object.
I want to do something like this:
public class SimpleClass
{
public DateTime ADate {get; set;}
public string StringHere {get; set;}
public int ANumber {get; set;}
}
var testObj = new SimpleClass();
// set values here on testObj properties
DoStuffHere(testObj, StringHere, ANumber);
I could pass in the properties as strings and then use reflection to get the properties from the passed in object, but I wanted to know if there was some way I could pass in the properties themselves so I could have intellisense and compile time checking to prevent bad property names. I would like my getNewClass function to take any type of object, and such, be generic.
Edit: I am not returning a new anonymous type. I think my function name was making it sound that way. I am going to be selecting a new anonymous type internally from a list of that specified testObj and generating a PDF from those properties.
Defining an anonymous type is actually very complicated, and trying to do it just with the names is somewhat challenging. Essentially what you want already exists, but in regular C# - so for a single object:
var obj = new { testObj.StringHere, testObj.ANumber };
Or for multiple objects:
var projection = from obj in sequence
select new { obj.StringHere, obj.ANumber };
That's about as succinct as you'll get. You could add a generic method that took a Func<,> of some kind, but it wouldn't be any cleaner than the above.
It isn't useful to have:
var obj = SomeMagicMethod(obj, "StringHere", "ANumber");
because SomeMagicMethod could only usefully return object - our obj variable would be largely unusable.
If you don't need to return the object from the method, then you could use either of:
SomeMagicMethod<T>(T value) {
...
}
...
SomeMagicMethod(new {testObj.StringHere, testObj.ANumber });
or:
SomeMagicMethod<TFrom, TTo>(TFrom value, Func<TFrom, TTo> selector)
{
TTo actualVal = selector(value);
...
}
...
SomeMagicMethod(testObj, x => new {x.StringHere, x.ANumber });
Personally, I think the first is easier - the func in the second is overkill.
You could also just use reflection...
SomeMagicMethod(object obj, params string[] names)
{
foreach(var name in names) {
object val = obj.GetType().GetProperty(name).GetValue(obj);
// ...
}
}
//...
SomeMagicMethod(testObj, "StringHere", "ANumber");
you can pass them as lambda:
GetNewClass (testObj, ()=>StringHere, ()=> ANumber);
and have a signature for GetNewClass like
void GetNewClass (object, Expression<Func<object>> expr0, Expression<Func<object>> expr1);
You can then get the property quite easily.
You can use Linq expressions for that.
(note: it's possible you need to modify a few things in the snippet below, this is of the top of my hat):
public void getNewClass(Object testObj, params MemberExpression Fields[])
{
foreach(MemberExpression field in Fields)
{
// Get the name
var name = field.Member.Name;
// get the value
var member= Expression.Convert(field, typeof(object));
var lambda= Expression.Lambda<Func<object>>(member);
var fnc= lambda.Compile();
var value = fnc();
}
}
This snippet show how to get the name of the property and the value. It can be called like this:
getClass(someObj, obj => obj.SomeProperty, obj.SomeOtherProperty);
Lets say i have the following code
private Func<T> _method;
public void SetExecutableMethod<T>(Func<T> methodParam)
{
_method = methodParam;
}
public T ExecuteMethod(object[] parameterValues)
{
//get the number of parameters _method has;
var methodCallExpression = _method.Body as MethodCallExpression;
var method = methodCallExpression.Method;
ParameterInfo[] methodParams = method.GetParameters();
//So i now have a list of parameters for the method call,
//How can i update the parameter values for each of these?
for (int i = 0; i < parameters.Count(); i++ )
{
methodParams[i] = ???''
}
return _method.Compile()();
}
public void InitAndTest()
{
SetExecutableMethod( () => _service.SomeMethod1("param1 placeholder", "param2 placeholder") );
T result1 = ExecuteMethod(new object[]{"Test1", "Test2"});
T result2 = ExecuteMethod(new object[]{"Test3", "Test4"}););
}
In the above code, i want to set a private variable to some Func that points to an anonymoust function and never have to set it again.
I then would like to be able to call ExecuteMethod(...) with different parameters. This method should update the parameter values of the variable _method and then invoke the method.
I can read the number of parameters and their values fine, i just am not sure how to set the values for those parameter? Any thoughts on this?
This is not the way to do it. Right now, your _method field is a delegate of type Func<T>, and you expect that its body contains yet another method which is actually executed. That is a lot to expect from your callers. I would forget about this approach and look for something different.
One way would be to supply a method which takes an array of objects as its parameter (Func<object[], T>), and then invoke it directly with appropriate parameters (but never a method in its body). Even this is less common for a strongly typed language like C# since you lose all type safety (but then again, you do want to be pretty flexible with this framework you are designing).
The other way would be to get a MethodInfo instance, and then use its Invoke method. In a way, this might even express your intents better, because it will be obvious that the executable method is capable of virtually anything.
Next, you could use generics to get some type safety, and require that all your input parameters are wrapped inside a single parameter class. In that case, you might have a strongly typed Func<Tparam, Tresult> method, and your Execute method would accept a Tparam instance as its parameter. This would void the need for any reflection.
[Edit]
As I wrote, I would try to avoid reflection. Since you wrote you basically need a cache of method results, a simple approach might be something like:
Create a wrapper for your list of parameters so that you can compare them "by value". I added an example class, but you might even want to allow passing an IEqualityComparer explicitly, so that you don't have to override Equals for each partial parameter.
// implements `IEquatable` for a list of parameters
class Parameters : IEquatable<Parameters>
{
private readonly object[] _parameters;
public Parameters(object[] parms)
{
_parameters = parms;
}
#region IEquatable<Parameters> Members
public bool Equals(Parameters other)
{
if (other == null)
return false;
if (_parameters.Length != other._parameters.Length)
return false;
// check each parameter to see if it's equal
// ...
}
public override bool Equals(object obj)
{
return Equals(obj as Parameters);
}
public override int GetHashCode()
{ ... }
#endregion
}
Create a cache for a single service. Using the wrapper class above, it should simply check if a cached result exists:
// contains cached results for a single service
class CachedCallInfo
{
private readonly Func<object[], object> _method;
private readonly Dictionary<Parameters, object> _cache
= new Dictionary<Parameters, object>();
public CachedCallInfo(Func<object[], object> method)
{
_method = method;
}
public T GetResult<T>(params object[] parameters)
{
// use out Parameters class to ensure comparison
// by value
var key = new Parameters(parameters);
object result = null;
// result exists?
if (!_cache.TryGetValue(key, out result))
{
// do the actual service call
result = _method(parameters);
// add to cache
_cache.Add(key, result);
}
return (T)result;
}
}
Create the final class which will reference services by name:
public class ServiceCache
{
private readonly Dictionary<string, CachedCallInfo> _services =
new Dictionary<string, CachedCallInfo>();
public void RegisterService(string name, Func<object[], object> method)
{
_services[name] = new CachedCallInfo(method);
}
// "params" keyword is used to simplify method calls
public T GetResult<T>(string serviceName, params object[] parameters)
{
return _services[serviceName].GetResult<T>(parameters);
}
}
Your cache setup will then look like this:
serviceCache.RegisterService("ServiceA", #params => DoSomething(#params));
serviceCache.RegisterService("ServiceB", #params => SomethingElse(#params));
And you would simply call it like this:
var result = serviceCache.GetResult("ServiceA", paramA, paramB, paramC);
Not sure why this is useful, but here goes:
public class SomeCrazyClass<T>
{
private Expression<Func<T>> _method;
public void SetExecutableMethod(Expression<Func<T>> methodParam)
{
_method = methodParam;
}
public object ExecuteMethod(SomeService someService, object[] parameterValues)
{
var methodCallExpression = _method.Body as MethodCallExpression;
var method = methodCallExpression.Method;
var methodCall = Expression.Call(Expression.Constant(someService), method,
parameterValues.Select(Expression.Constant));
return Expression.Lambda(methodCall).Compile().DynamicInvoke();
}
}
Call it like so:
public static void InitAndTest()
{
var something = new SomeCrazyClass<int>(); //or whatever type your method returns
var _service = new SomeService();
something.SetExecutableMethod(() => _service.SomeMethod1("param1 placeholder", "param2 placeholder"));
var result1 = something.ExecuteMethod(_service,new object[] {"Test1", "Test2"});
var result2 = something.ExecuteMethod(_service, new object[] {"Test3", "Test4"});
}
Personally, I think you're going WAY overboard, unless there is an overriding architecture need to deal with the lambda as an expression tree. But, I digress.
Instead of working with the reflective elements (which are basically for description only in terms of an expression tree), look at the Arguments member of your MethodCallExpression. It will contain several ContantExpression objects, which you can replace with your own ConstantExpressions containing the string values you want to pass in. However, Expressions are read-only; you have to rebuild an equivalent tree for this call.
public class FuncManipulator<T>
{
private Func<T> _method;
public void SetExecutableMethod(Func<T> methodParam)
{
_method = methodParam;
}
//you forgot the "params" keyword
public T ExecuteMethod(params object[] parameterValues)
{
//get the number of parameters _method has;
var methodCallExpression = _method.Body as MethodCallExpression;
var arguments = methodCallExpression.Arguments;
var newArguments = new List<Expression>();
for (int i = 0; i < arguments.Count(); i++ )
{
newArguments.Add(Expression.Constant(parameterValues[i]));
}
//"Clone" the expression, specifying the new parameters instead of the old.
var newMethodExpression = Expression.Call(methodCallExpression.Object,
methodCallExpression.Method,
newArguments)
return newMethodExpression.Compile()();
}
}
...
public void InitAndTest()
{
SetExecutableMethod( () => _service.SomeMethod1("param1 placeholder", "param2 placeholder") );
T result1 = ExecuteMethod("Test1", "Test2");
T result2 = ExecuteMethod("Test3", "Test4");
T result3 = ExecuteMethod("Test6", "Test5");
}
This will work as long as the expression tree can find the Func referred to by MethodCallExpression.method within the current instance.
However, I think there's a much simpler way:
public class FuncManipulator<T>
{
private Func<T> _method;
public void SetExecutableMethod(Func<T> methodParam)
{
_method = methodParam;
}
//you must pass the actual array; we are creating a closure reference that will live
//as long as the delegate
public void SetMethodParams(object[] param)
{
_param = param;
}
public T ExecuteMethod(params object[] passedParam)
{
//We have to re-initialize _param based on passedParam
//instead of simply reassigning the reference, because the lambda
//requires we don't change the reference.
for(int i=0; i<_param.Length; i++)
_param[i] = passedParam.Length <= i ? null : passedParam[i];
//notice we don't pass _param; the lambda already knows about it
//via the reference set up when declaring the lambda.
return _method();
}
}
...
public void InitAndTest()
{
//this is an "external closure" we must keep in memory
object[] param = new object[2];
SetExecutableMethod( () => _service.SomeMethod1(param[0], param[1]) );
//We do so by passing the reference to our object
SetMethodParams(param);
//now, don't ever reassign the entire array.
//the ExecuteMethod function will replace indices without redefining the array.
T result1 = ExecuteMethod("Test1", "Test2");
T result2 = ExecuteMethod("Test3", "Test4");
T result3 = ExecuteMethod("Test6", "Test5");
}