The type arguments cannot be inferred from the usage. Try specifying the type arguments explicitly
Asked Answered
T

9

41

Could someone please clarify something for me. In my ASP.NET MVC 2 app, I've got a BaseViewModel class which includes the following method:

public virtual IDictionary<string, object> GetHtmlAttributes<TModel, TProperty>
                        (Expression<Func<TModel, TProperty>> propertyExpression)
{
    return new Dictionary<string, object>();
}

The idea being that each child viewmodel can override this method and provide a suitable set of html attributes, based on some logic, to be rendered in the view:

<%: Html.TextBoxFor(model => model.MyProperty, Model.GetHtmlAttributes
                                                 (model => model.MyProperty)) %>

However when used as in the line above, I get a compilation error when I hit the view:

The type arguments for method '...BaseViewModel.GetHtmlAttributes<TModel,TProperty> Expression<System.Func<TModel,TProperty>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

I have to do the following:

<%: Html.TextBoxFor(model => model.MyProperty, Model.GetHtmlAttributes
                             <ChildModel, string>(model => model.MyProperty)) %>

I'm just looking for some clarity as to how it tries to infer the type, it has no problem doing so in the HtmlHelper/TextBoxFor extension method?

Is it because HtmlHelper in the view will automatically be for the same type as is specified in the ViewUserControl at the top of the page, whereas my code can be for any type inheriting from BaseViewModel? Is is possible to write this in such a way that it can infer my model/property types?

Theocritus answered 11/2, 2011 at 13:5 Comment(2)
Holy horizontal scrollbars batman!Nerynesbit
Yeah totally. It's absurd on our 30" monitors that we get just 6.5" for scrolling code back and forth in these tiny windows. Come on SA guys, take your VC money and get with dynamic page sizing!Vase
E
15

In your example, the compiler has no way of knowing what type should TModel be. You could do something close to what you are probably trying to do with an extension method.

static class ModelExtensions
{
   public static IDictionary<string, object> GetHtmlAttributes<TModel, TProperty>
      (this TModel model, Expression<Func<TModel, TProperty>> propertyExpression)
   {
       return new Dictionary<string, object>();
   }
}

But you wouldn't be able to have anything similar to virtual, I think.

EDIT:

Actually, you can do virtual, using self-referential generics:

class ModelBase<TModel>
{
    public virtual IDictionary<string, object> GetHtmlAttributes<TProperty>
        (Expression<Func<TModel, TProperty>> propertyExpression)
    {
        return new Dictionary<string, object>();
    }
}

class FooModel : ModelBase<FooModel>
{
    public override IDictionary<string, object> GetHtmlAttributes<TProperty>
        (Expression<Func<FooModel, TProperty>> propertyExpression)
    {
        return new Dictionary<string, object> { { "foo", "bar" } };
    }
}
Expansible answered 18/4, 2011 at 21:53 Comment(1)
This works fine in this case, but it's not acceptable for some HtmlHelper extensions. Indeed, I created the following extension : public static IHtmlContent EnumCheckBoxListFor<TModel, TEnum>(this IHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TEnum>>> expression, object htmlAttributes = null) . In this case, I can't use the virtual/override workaround (and I can't see any "clean" solution). Note that when I call it in my View, the Model type can be inferred whereas the Enum one cannot.Vostok
B
19

I know this question already has an accepted answer, but for me, a .NET beginner, there was a simple solution to what I was doing wrong and I thought I'd share.

I had been doing this:

@Html.HiddenFor(Model.Foo.Bar.ID)

What worked for me was changing to this:

@Html.HiddenFor(m => m.Foo.Bar.ID)

(where "m" is an arbitrary string to represent the model object)

Billibilliard answered 27/10, 2012 at 2:15 Comment(0)
E
15

In your example, the compiler has no way of knowing what type should TModel be. You could do something close to what you are probably trying to do with an extension method.

static class ModelExtensions
{
   public static IDictionary<string, object> GetHtmlAttributes<TModel, TProperty>
      (this TModel model, Expression<Func<TModel, TProperty>> propertyExpression)
   {
       return new Dictionary<string, object>();
   }
}

But you wouldn't be able to have anything similar to virtual, I think.

EDIT:

Actually, you can do virtual, using self-referential generics:

class ModelBase<TModel>
{
    public virtual IDictionary<string, object> GetHtmlAttributes<TProperty>
        (Expression<Func<TModel, TProperty>> propertyExpression)
    {
        return new Dictionary<string, object>();
    }
}

class FooModel : ModelBase<FooModel>
{
    public override IDictionary<string, object> GetHtmlAttributes<TProperty>
        (Expression<Func<FooModel, TProperty>> propertyExpression)
    {
        return new Dictionary<string, object> { { "foo", "bar" } };
    }
}
Expansible answered 18/4, 2011 at 21:53 Comment(1)
This works fine in this case, but it's not acceptable for some HtmlHelper extensions. Indeed, I created the following extension : public static IHtmlContent EnumCheckBoxListFor<TModel, TEnum>(this IHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TEnum>>> expression, object htmlAttributes = null) . In this case, I can't use the virtual/override workaround (and I can't see any "clean" solution). Note that when I call it in my View, the Model type can be inferred whereas the Enum one cannot.Vostok
P
14

I had this same problem, my solution:
In the web.config file :

<compilation debug="true>
had to be changed to
<compilation debug="true" targetFramework="4.0">

Philosophy answered 16/12, 2011 at 17:9 Comment(3)
Thanks a LOT Jim! You have saved my day, I Googled for days and didn't find a solution on main questions but then find yours here in a small comment! I'm using VS 2012 that comes with MVC 4.0, and yes adding the targetFramework="4.0" solved the problems with red lines under ViewBag, Html.TextboxFor, etc.Longdrawn
I opened a new Question with more related title, used your answer and have credit for it. Hope it helps others.Longdrawn
Thanks Jim, you saved my day. Can you explain why this targetFramework is important? how did you figure this out?Ebonyeboracum
T
4

This error is also related with a cache issue.

I had the same problem and it was solved just cleaning and building the solution again.

Toscanini answered 11/1, 2016 at 15:12 Comment(2)
For me it was also a caching issue, but it only got resolved after restarting Visual Studio. For me this happened after updating the namespaces of the models that were being referenced.Drippy
Came across this and it was caching for me too!Oxa
F
4

I was actually searching for a similar error and Google sent me here to this question. The error was:

The type arguments for method 'IModelExpressionProvider.CreateModelExpression(ViewDataDictionary, Expression>)' cannot be inferred from the usage

I spent maybe 15 minutes trying to figure it out. It was happening inside a Razor .cshtml view file. I had to comment portions of the view code to get to where it was barking since the compiler didn't help much.

<div class="form-group col-2">
    <label asp-for="Organization.Zip"></label>
    <input asp-for="Organization.Zip" class="form-control">
    <span asp-validation-for="Zip" class="color-type-alert"></span>
</div>

Can you spot it? Yeah... I re-checked it maybe twice and didn't get it at first!

See that the ViewModel's property is just Zip when it should be Organization.Zip. That was it.

So re-check your view source code... :-)

Forestaysail answered 13/6, 2020 at 22:48 Comment(2)
Thank you for that. I had the same problem here and this answer helped me greatly. Looks like using an inexistent property name on "asp-for" or "asp-validation-for" causes that exception.Dara
Saved my life. There is no chance to find problem with my own eyes. And created this blog post: dev.ozanbayram.com/post/2022/04/01/…Falstaffian
M
3

C# compiler have only lambda

arg => arg.MyProperty

for infer type of arg(TModel) an type of arg.MyProperty(TProperty). It's impossible.

Method answered 12/4, 2011 at 14:1 Comment(0)
J
0

In case it helps, I've ran into this problem when passing null into a parameter for a generic TValue, to get around this you have to cast your null values:

(string)null

(int)null

etc.

Jarl answered 28/2, 2013 at 17:55 Comment(0)
E
0

Just to add another possible solution/issue, I was updating the password but the DB Model did not have any Password Property, so I created a View Model.

 <div class="form-group">
            <label asp-for="user.Password"></label>
            <input asp-for="user.Password" class="form-control" />
            <span asp-validation-for="user.Password" class="text-danger"></span>
  </div>
Expiry answered 12/12, 2021 at 14:44 Comment(0)
V
-3

You are referring to the type rather than the instance. Make 'Model' lowercase in the example in your second and fourth code samples.

Model.GetHtmlAttributes

should be

model.GetHtmlAttributes
Vase answered 13/2, 2011 at 7:12 Comment(1)
thanks for the suggestion, but i need to give it a specific instance of a model object (exposed the view's Model property). 'model' doesn't actually exist in the context of the htmlAttributes parameter of the TextBoxFor helper.Theocritus

© 2022 - 2024 — McMap. All rights reserved.