views:

320

answers:

1

I have written a List`1 editor template for use with the EditorFor extension methods (MVC2), however I am running into issues when using generics + null objects.

Given a model

class MyModel {
   public Foo SomeFoo { get;set; }
   public List<Foo> SomeFooList { get;set; }
 }

and a template in /Views/Shared/EditorTemplates/List`1.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<%
    IEnumerable enumerableModel;
    if (Model != null && (enumerableModel = Model as IEnumerable) != null)
    {
        foreach (var v in enumerableModel)
        {
            var model = v;
            Response.Write(Html.EditorFor(m => model));
        }
    }
%>

I get the expected editor for SomeFoo, and any elements of SomeFooList which are not null, as the type in ModelMetaData will be "Foo". However, if I have "null" as one of the objects in SomeFooList, I get nothing rendered as model is of type "object" and not Foo or more generically T from my list's generic arguments.

Essentially I would like to achieve something like

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<T>> where T : class" %>

so I know the types of my list.

I could also look at changing the ModelMetaData.ModelType field in the case of a null (by creating a new object, as this is readonly) -- but this is one of those nasty hacks I would like to avoid.

Another thought is calling the EditorFor method with .Invoke and passing typeof(T) into there, but again, I would like to avoid this type of code if possible.

Any thoughts?

Update:

Trying to get the type into model meta data was looking a little trickier than I first expected. I have updated my code with the following which seems to work, but I am still not too keen on the solition:

if (Model != null && (enumerableModel = Model as IEnumerable) != null)
    {
        Type listType = null;

        if (enumerableModel.GetType().IsGenericType)
        {
            listType = enumerableModel.GetType().GetGenericArguments()[0];
        }

        foreach (var v in enumerableModel)
        {
            var model = v;
            if (model == null && listType != null)
                model = Activator.CreateInstance(listType);
            Response.Write(Html.EditorFor(m => model));
        }
    }

Amar

+1  A: 

Maybe you could think about creating a custom structure similar to Nullable<T> to contain your entity? Nullable<T> contrains T to be a struct which is why you'd have to create your own one. That way you can check a HasValue property rather than having the problem with checking null and not knowing the type.

Charlie
By the way, if some could show me how to write Nullable< T > properly in this markdown without having to put in spaces, I'd be greatful!
Charlie
Wrap it inside backticks (```) and you get `Nullable<T>`.
LukeH
That seems fair, I will have a play with this tomorrow and see if I can get anything from it. Cheers
amarsuperstar