I would like to get a delegate to a property´s set function. This is how I do today:
var property = typeof(IApplicationState).GetProperty(propertyName);
var action = (Action<IApplicationState, T>)Delegate.CreateDelegate(typeof(Action<IApplicationState, T>), null, property.GetSetMethod());
This works, but then I have know the name of the property.
Can I do this without using the name? Something like this:
var action = (Action<IApplicationState, T>)Delegate.CreateDelegate(typeof(Action<IApplicationState, T>), null, IApplicationState.PROPERTY.GetSetMethod());
One simple option which does introduce an extra hop (but would probably have negligible performance impact) would be to just use a lambda expression:
Action<IApplicationState, T> action = (state, value) => state.Foo = value;
There's currently no way of referring to a property at compile-time in the same way as we can refer to a type with typeof - although it's on the C# team's feature request list.
EDIT: If this is in a generic method (with a type parameter of T), it's not at all clear to me that you'll be able to use this directly, as state.Foo would presumably have to be of type T (or object perhaps). We can't really help with that aspect without more context of what you're trying to achieve.
Related
I was wondering something like the the following is possible
int foo = GetDefaultValue();
object GetDefaultValue() // Example function, behavior is not the purpose of this question
{
Type t = // Reflection magic
if (t.IsValueType)
return Activator.CreateInstance(t);
return null;
}
I know something similar exists with the CallerMemberNameAttribute attribute, but it doesn't give me what I'm looking for.
I know I can use generics, pass type as parameter etc, but I was curious if it's possible with reflection (just curiosity)
As was mentioned in the comments, default values are already part of the language:
int myInteger = default;
You don't need anything extra for this.
I know I can use generics, pass type as parameter etc, but I was curious if it's possible with reflection (just curiosity)
Reflection on what?
You're not passing anything. Reflection either involves instantiation based on a dynamically passed type, or typing/accessing properties based on a dynamically passed object.
But you're not providing a type or an instance, so there is nothing to reflect on here.
I was looking at some code at work and came across something I'm not familiar with.
here is full property im familiar with:
private int myVar;
public int MyProperty
{
get { return myVar; }
set { myVar = value; }
}
but then I saw (and I can't recall exactly) this:
private int myVar = x => x.Something;
This was found in application that uses CSLA.
Biscuits wrote about property (or field) selectors... There are two uses for these: one (the one he spoke about) to get the name of the field/property.
How to do it?
Given:
Expression<Func<Foo, int>> expression = x => x.Something;
You do:
string name = ((MemberExpression)expression.Body).Member.Name;
as written by others, in C# 6.0 this will become nearly useless thanks to nameof() (that in general is faster because it's done at compile time instead that at runtime) and in C# 5.0 partially useless thanks to [CallerMemberName].
The second use is that, by passing an Expression<> that is a "getter" (a function that given an object returns the value of something) to a method, the method can "build" a "setter".
Func<Foo, int> getter = expression.Compile();
var parameter = Expression.Parameter(expression.ReturnType);
Action<Foo, int> setter = Expression.Lambda<Action<Foo, int>>(
Expression.Assign(expression.Body, parameter ),
new[] { expression.Parameters[0], parameter }).Compile();
Foo foo = new Foo();
setter(foo, 5); // Example of use of the setter
int value = getter(foo); // Example of use of the getter
If you have to use a single time the setter, this is quite slower than using directly reflection (because the Expressions must be built, then compiled and and so on, and in the building and compiling (but not in the using) of the Expression there is use of reflection). But if you need to use many times the getter/setter, then it become faster (if you "cache" them), because the use of a getter/setter built in this way is nearly as much fast as accessing the property/field directly (the slow part is in the creation of the getter/setter)
Using a lambda expression as a variable (public or private) is like using a function that can change.
for example i could do something like this
var myFavoriteFunction = (x) => x.FirstFunction();
//do some work
myFavoriteFunction(someobject)
//now change the function
myFavoriteFunction = (x) => x.SecondFunction();
myFavoriteFunction(someobject)
without knowing the code you are looking at, you might think of this as a click handler, and the function being executed when clicking the button can change. (of course a click handler you could also do differently but that's beside the point)
Using expressions in this way is also called a property selector.
The correct syntax for this is actually like so.
private Expression<Func<Foo, int>> myVar = x => x.Something;
There are countless uses for these, and one typical example is to avoid having to "hard-code" member names that must otherwise be typed as string literals (which remain unchecked by the compiler and proves difficult to refactor).
Here's one practical application for this example.
Implementing INotifyPropertyChanged - does a better way exist?
You also see this heavily used in Fluent interface implementations, such as Fluent NHibernate.
In the advent of the nameof() expression coming in C# 6, however, we could soon see this technique fade.
http://davefancher.com/2014/12/02/c-6-0-nameof-expressions/
What you saw was not related to a property, it was a delegate assignation. (The type was probably not an int)
Func<int,int> doubleMyNumber = (i) => 2 * i;
This works like a delegate, written as an anonymous function. More information here: https://msdn.microsoft.com/fr-fr/library/bb397687.aspx
In C# 6 you'll be able to see even stranger notations like this
public int AgeInDogYears() => Age * 7;
You'll be able to write the method's body as a lambda expression. http://csharp.2000things.com/2014/11/03/1217-using-lambda-expressions-for-function-members/
can i have something like:
AMess.Foo = MessyData.GetData<MessyData.GetType(key)>(key);
?
my problem is similar to my example. I have a data source is dynamically typed, so i have to do something to determine the data type. but it's a pain in the ass to put type check everywhere. so i think maybe i could have some code just to tell me what type it is. can i do this?
or maybe better solution?
please not worry about AMess.Foo, it eats everything.
No, it can't. You'll have to use Reflection instead. I don't have Visual Studio installed on my machine at the moment so I can't test the syntax at the moment, but this should be close:
var type = MessyData.GetType(key);
var castMethod = MessyData.GetType().GetMethod("GetData").MakeGenericMethod(type);
AMess.Foo = castMethod.Invoke(MessyData, new[] { key });
No. Generic type arguments must be resolved at compile-time.
If you use:
MessyData.GetData<SomeType>(key);
then SomeType needs to be the name of a specific class (or interface, struct, etc.). It can never be an expression like in your question.
If you let the type be inferred, as in:
MessyData.GetData(key); // infer type arg
then the type used in the call is the compile-time type of the key variable, not the run-time type. These types can differ.
If you really want dynamic typing, you can have GetData take in a parameter of type dynamic (the method will be non-generic). But what is the problem you are trying to solve?
My apologies if the question is somewhat unclear; I'm not entirely certain how to phrase this.
My issue is this. I have two classes, Manager<T> and Result<T>. Within Manager<T>, I have a whole raft of retrieval functions. Ordinarily, I would call Manager<T> and set its type like so:
Manager<SpecialDataType> mgr = new Manager<SpecialDataType>;
After which I set up my Result type, and fill it with my function from Manager, where 1 is a parameter for the GetItem function shown. I can then access things in my item:
Result<SpecialDataType> item = new Result<SpecialDataType>;
item = mgr.GetItem(1);
string x = item.Teaser;
OK. So now, what I'm trying to do is set the <SpecificDataType> to be filled in at run time. I think I've got half of the solution already, using generic types, like so:
Type generalType= Type.GetType("SpecificDataType");
Type managerType= typeof(Manager<>).MakeGenericType(generalType);
var managerInstance= Activator.CreateInstance(managerType);
object[] args = {1};
MethodInfo getItemMethod = managerInstance.GetMethod("GetItem");
But here's where I get stuck. There are specific properties that my Result class has that I need to be able to access. They are, or course, set by the data type I'm casting into. When I do an Invoke, like so:
var item = getItemMethod.Invoke(managerInstance, args);
I'm not getting any of my properties that I know are part of item. That makes sense, I suppose, because we don't know what item is. So, we tried this:
Type dataType = typeof(SmartFormData<>).MakeGenericType(sfType);
var item = Activator.CreateInstance(dataType);
item = getItemMethod.Invoke(managerInstance, args);
And got the same result. I can't seem to get to item.Teaser.
I'm not a c# coder natively (as though that's not apparent already from this overly complicated question I'm asking), so I'm not incredibly familiar with reflection and generic types. Can anyone point me in the right direction for how to solve this problem, or how to approach it from a different angle? The only caveat is that I cannot modify the Manager<T> and Result<T> functions; I have to use what I'm given there.
Thanks in advance for any help you can offer.
As Dark Falcon correctly notes in his comment you will have to use reflection to get the members of your item.
Or, if you are in .NET 4 or above, you can use the dynamic keyword to greatly simplify things:
Type generalType= Type.GetType("SpecificDataType");
Type managerType= typeof(Manager<>).MakeGenericType(generalType);
dynamic managerInstance = Activator.CreateInstance(managerType);
var item = managerInstance.GetItem(1);
string x = item.Teaser;
You need to cast the invocation result to the type you're expecting
var item = (Result<SpecificDataType>)getItemMethod.Invoke(managerInstance, args);
What I'm trying to do is call the method of a property, using Reflection. I have the original Control (a ComboBox), the PropertyInfo of the property (ComboBox.Items) and the name of the method (ComboBox.Items.Add). I've tried the code below to get, alter, set but it doesn't work because Items doesn't have a setter.
PropertyInfo p = controlType.GetProperty(propertyName); // gets the property ('Items')
MethodInfo m = p.PropertyType.GetMethod(methodName); // gets the method ('Items.Add')
object o = p.GetValue(newControl, null); // gets the current 'Items'
m.Invoke(o, new object[] { newValue }); // invokes 'Add' which works
p.SetValue(newControl, o, null); // exception: 'Items' has no setter
Does anyone have any advice?
Thanks
That was quick... I changed the Invoke line to...
m.Invoke(p.GetValue(newControl, null), new object[] { newValue });
...and it worked :P
#acron, Thanks for providing a great question and answer. I want to extend your solution for a slightly different scenario for anyone looking in the future.
Facing a similar problem in the ASP.NET world I was trying to find a common way to load either a System.Web.UI.Webcontrols.DropDownList OR a System.Web.UI.HtmlControls.HtmlSelect While both of these have an "Items" property of type "ListItemCollection", with a corresponding "Add" method, they do not share a common interface (as they SHOULD... hey Microsoft...) so that casting can be used.
The additional challenge that your solution didn't provide for is the overloading of the Add method.
Without the overloads your line:
MethodInfo m = p.PropertyType.GetMethod(methodName);
works just fine. But, when the Add method is overloaded an additional parameter is called for so that the runtime can identify which overload to invoke.
MethodInfo methInfo = propInfo.PropertyType.GetMethod("Add", new Type[] { typeof(ListItem) });
The error that you are getting indicates that the property in question is read only. There is no set method defined. You will not be able to set the value for the property without a setter.
Post back with the name of the property or more context and we may be able to give you a better answer or an alternative.