1

我正在尝试构建一个通用模型绑定器,该模型绑定器使用反射将属性分配给从 BindingContext 检索的指定类型的对象。所以是这样的:

public class ModelBinder : IModelBinder
{
    public object BindModel<T, K> (ControllerContext controllerContext, ModelBindingContext bindingContext)
        where T : class, new()
        where K : class
    {
        Type ObjectType = typeof(T);
        Type InterfaceType = typeof(K);
        T obj = new T();

        foreach (var Property in ObjectType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance))
        {
            Type PropertyType = Property.PropertyType;

            // checks if property is a custom data object
            if (!(PropertyType.GetGenericArguments().Count() > 0 && PropertyType.GetGenericArguments()[0].GetInterfaces().Contains(InterfaceType)))
            {
                Property.SetValue(obj, bindingContext.ValueProvider.GetValue(Property.Name), null);   
            }
        }

        return obj;
    }

显然这不起作用,因为它没有正确实现 IModelBinder 接口。这样的事情可能吗?

编辑:

为了扩展我这样做的原因,我们的对象使用了许多不同的自定义对象。例如,类对象:

public class Class : ModelBase<Class>
{
    public Class () { }

    public virtual string ClassDescription { get; set; }
    public virtual string ClassName { get; set; }
    public virtual LookUp ClassType { get; set; }
    public virtual double Credits { get; set; }
    public virtual bool Documents { get; set; }
    public virtual LookUp PracticeArea { get; set; }
}

使用 LookUp 类:

public class LookUp : ModelBase<LookUp>
{
    public LookUp () { }

    public virtual string DisplayName { get; set; }
    public virtual LookUpType Type { get; set; }
}

下拉列表用于查找和其他对象,因此我的类/创建自定义模型绑定器将执行以下操作:

LookUp ClassType = LookUp.Load(long.Parse(bindingContext.ValueProvider.GetValue("ClassType").AttemptedValue))

我看不出如何使用 DefaultModelBinder 来处理这样的事情。

4

1 回答 1

2

所以我想出了一个可行的(目前)解决方案。目前它不是很通用,但它适用于我的目的。

public class ModelBinder : DefaultModelBinder
{
    public override object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var ModelType = bindingContext.ModelType;
        var Instance = Activator.CreateInstance(ModelType);
        var Form = bindingContext.ValueProvider;

        foreach (var Property in ModelType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance))
        {
            Type PropertyType = Property.PropertyType;

            // I'm using an ORM so this checks whether or not the property is a
            // reference to another object
            if (!(PropertyType.GetGenericArguments().Count() > 0 ))
            {
                // This is the not so generic part.  It really just checks whether or 
                // not it is a custom object.  Also the .Load() method is specific
                // to the ORM
                if (PropertyType.FullName.StartsWith("Objects.Models"))
                {
                    var Load = PropertyType.GetMethod("Load", BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static, null, new Type[] { typeof(long) }, null);
                    var Value = Load.Invoke(new object(), new object[] { long.Parse(Form.GetValue(Property.Name + ".ID").AttemptedValue) });
                    Property.SetValue(Instance, Value, null);
                }
                // checkboxes are weird and require a special case
                else if (PropertyType.Equals(typeof(bool)))
                {
                    if (Form.GetValue(Property.Name) == null)
                    {
                        Property.SetValue(Instance, false, null);
                    }
                    else if (Form.GetValue(Property.Name).Equals("on"))
                    {
                        Property.SetValue(Instance, true, null);
                    }
                }
                else
                {
                    Property.SetValue(Instance, Convert.ChangeType(bindingContext.ValueProvider.GetValue(Property.Name).AttemptedValue, PropertyType), null);
                }
            }
        }

        return Instance;
    }
}
于 2012-10-17T22:18:35.760 回答