How to get instance of T of an Expression<Func<T, TK>> - c#

Is it possible to get the instance of TModel from Expression in the following method?
public void FooBar<TModel, TProperty> MyMethod(
Expression<Func<TModel, TProperty>> expression)
where TModel : ViewModel
{
ViewModel model = ???;
}

There is no instance, and as such there is no way to get the instance that doesn't exist.
The expression is merely an object that says, "If you give me a model, I know how to give you back a property of it." It doesn't actually have a model until you give it a model.

Related

Implicit defined generic types, is this possible?

I currently want to write a generic extension method. If every generic type is availible in the parameters, I do not need to define the generic types:
//Extension Method
public static GridBoundColumnBuilder<TModel>
BoundEnum<TModel, TValue>(this GridColumnFactory<TModel> factory,
Expression<Func<TModel, TValue>> expression);
//I can call It this way, whitout setting <TModel, TValue>
columns.BoundEnum(c => c.SomeProp);
If I want to add a generic type, that is not covered in the parameters, I need to set <TModel, TValue>:
//Extension Method
public static GridBoundColumnBuilder<TModel>
BoundEnum<TModel, TValue, TEnum>(this GridColumnFactory<TModel> factory,
Expression<Func<TModel, TValue>> expression)
//How it works:
columns.BoundEnum<TModel, TValue, TEnum>(c => c.SomeProp);
Is there a way that I can only write this?
columns.BoundEnum<TEnum>(c => c.SomeProp);
Edit: This is the full Method:
public static GridBoundColumnBuilder<TModel>
BoundEnum<TModel, TValue, TEnum>(this GridColumnFactory<TModel> factory,
Expression<Func<TModel, TValue>> expression)
where TModel : class
where TEnum : struct, IComparable
{
return factory.ForeignKey(expression, EnumHelper.ToSelectList<TEnum>());
}
If the compiler cannot infer all generic types then you have to pass them all. There's no support for partial inference.

Explanation of usage generic method with an expression

I want to pass in a strongly types property to a method and use this propertyname as a string for mhy collection, so I found some code where I can pass my property strongly typed:
public static void Add<TObject, TProperty>(this NameValueCollection collection, Expression<Func<TObject, TProperty>> expression, string value)
{
var member = expression.Body as MemberExpression;
collection.Add(member.Member.Name, value);
}
This works and does what I want, but I was wondering how this exactly works. The part I am interested in is the generic arguments of the method (Add<Tobject, TProperty>) in combination with the Func expression. Can someone explain to me how this works? And why I can call this method like collection.Add((MyObject m) => m.FullName, "Martijn")? Why isn't it necessarly to use Add<MyObject, ???>(m => m.FullName, "Martijn")?
Update:
I now have my method refactored to this:
public static void Add<TObject>(this NameValueCollection collection, Expression<Func<TObject, string>> expression, string value)
{
var member = expression.Body as MemberExpression;
collection.Add(member.Member.Name, value);
}
Expression<T> is an expression tree that has the signature of delegate-type T. Expression trees are complex, but basically: instead of being a delegate that is the operation, this is an object-model that describes the operation, and that can be inspected to see how it is composed.
Thus, an Expression<Func<TObject,TProperty>> is an expression-tree representing something that accepts TObject parameter and returns TProperty result.
As for why you don't need to tell it the <MyObject, ???> manually: that is generic type inference, and is normal. Given a generic method, say:
void Foo<T>(T bar);
You can call that as:
Foo<string>("abc");
but you can also use:
Foo("abc");
The compiler will then inspect the parameters to see if it can resolve all of the generic type parameters - in this case, the "abc" is a string and pins T to being a string. If it can resolve all of them, you don't need to specify them.
In your example, the TObject is pinned because your lambda explicitly takes a MyObject, via (MyObject) m, and the TProperty is pinned to (presumably) a string, because m.FullName (presumably) returns a string. Since all the generic type parameters have been resolved automatically you do not need to specify the <...> manually.
Note that generic type inference only applies to generic methods (via the parameters), not to generic types.

Get reference to object from c# expression

I have an extension generic method
public static void AddError<TModel>(
this ModelStateDictionary modelState,
Expression<Func<TModel, object>> expression,
string resourceKey,
string defaultValue)
{
// How can I get a reference to TModel object from expression here?
}
I need to get the reference to TModel object from expression.
This method called by the following code:
ModelState.AddError<AccountLogOnModel>(
x => x.Login, "resourceKey", "defaultValue")
You cannot get to the TModel object itself without passing it into the method. The expression you are passing in is only saying "take this property from a TModel". It isn't actually providing a TModel to operate on. So, I would refactor the code to something like this:
public static void AddError<TModel>(
this ModelStateDictionary modelState,
TModel item,
Expression<Func<TModel, object>> expression,
string resourceKey,
string defaultValue)
{
// TModel's instance is accessible through `item`.
}
Then your calling code would look something like this:
ModelState.AddError<AccountLogOnModel>(
currentAccountLogOnModel, x => x.Login, "resourceKey", "defaultValue")
I imagine you really want the text "Login" to use to add a new model error to the ModelStateDictionary.
public static void AddError<TModel>(this ModelStateDictionary modelState,
Expression<Func<TModel, object>> expression, string resourceKey, string defaultValue)
{
var propName = ExpressionHelper.GetExpressionText(expression);
modelState.AddModelError(propName, GetResource("resourceKey") ?? defaultValue);
}
Assume you have some resource factory/method that returns null if the resource isn't found, that's just for illustration.

How to get this expression value model => model.Name?

I am trying to get below expression value by compiling and invoking but i get some errors and no success till now.
public static void TextEditorFor<TModel, TProperty>(this System.Web.Mvc.HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
{
var value = expression.Compile().Invoke(html.ViewData.Model);//problem that is value is null
}
(applies to the original question)
Given the signature, you should just need:
return Convert.ToString(
expression.Compile().Invoke(modelInstance)
);
You can also do this by inspection of the expression if absolutely needed.
Use ModelMetadata.FromLambdaExpression Method and then its property Model

How do I get the value from an anonymous expression?

For sake of simplicity, imagine the following code:
I want to create a Foo:
public class Foo
{
public string Bar { get; set; }
}
And pass it to a special Html Helper method:
Html.SomeFunction(f => f.Bar);
Which is defined as:
public string SomeFunction<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
I want to get the value of Bar inside of this function, but have absolutely no idea how to get it.
Simply compile the expression and get the value.
Func<TModel, TValue> method = expression.Compile();
TValue value = method(html.ViewData.Model);
// might be a slightly different property, but you can get the ViewModel
// from the HtmlHelper object.
You will need to call Compile() on the expression to get the Func and then execute that.
public string SomeFunction<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
TValue valueOfBar = expression.Compile()(html.Model); // Assumes Model is accessible from html.
// Do stuff
}
Side note: If there isn't any need for the dynamic expressions or expression analysis you might as well pass the Func directly in instead.
For those that are using expression without MVT Model, one would obtain name and value of property in a following way.
public static string Meth<T>(Expression<Func<T>> expression)
{
var name = ((MemberExpression)expression.Body).Member.Name;
var value = expression.Compile()();
return string.Format("{0} - {1}", name, value);
}
use:
Meth(() => YourObject.Property);
in Microsoft.AspNetCore.Mvc.Rendering there is helpfull valuefor method;
public static string ValueFor<TModel, TResult>(this IHtmlHelper htmlHelper, Expression<Func<TModel, TResult>> expression);
public string SomeFunction<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression){
var valueOfExpression = html.ValueFor(expression);
//do your stuff
}
Using Compile() will use the Roslyn compiler-framework and will emit MSIL-code that will be dynamically loaded into your application. This executable code takes up memory, and in contrast to "normal" memory it is not subject to garbage collection nor can you free it yourself. If you do this too frequently (like regularly during SQL generation) you will run out of memory eventually. I ran into this issue and open-sourced my solutions as an open-source library:
https://www.nuget.org/packages/MiaPlaza.ExpressionUtils

Categories