// Copyright © 2016 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
namespace CefSharp.ModelBinding
{
///
/// Default binder - used as a fallback when a specific modelbinder
/// is not available.
///
public class DefaultBinder : IBinder
{
private static readonly MethodInfo ToArrayMethodInfo = typeof(Enumerable).GetMethod("ToArray", BindingFlags.Public | BindingFlags.Static);
///
/// Bind to the given model type
///
/// object to be converted into a model
/// the target param type
/// Bound model
public virtual object Bind(object obj, Type targetType)
{
if (obj == null)
{
if (targetType.IsValueType)
{
//For value types (int, double, etc) we cannot return null,
//we need to return the default value for that type.
return Activator.CreateInstance(targetType);
}
return null;
}
var objType = obj.GetType();
// If the object can be directly assigned to the modelType then return immediately.
if (targetType.IsAssignableFrom(objType))
{
return obj;
}
if (targetType.IsEnum && targetType.IsEnumDefined(obj))
{
return Enum.ToObject(targetType, obj);
}
var typeConverter = TypeDescriptor.GetConverter(objType);
// If the object can be converted to the modelType (eg: double to int)
if (typeConverter.CanConvertTo(targetType))
{
return typeConverter.ConvertTo(obj, targetType);
}
if (targetType.IsCollection() || targetType.IsArray() || targetType.IsEnumerable())
{
return BindCollection(targetType, objType, obj);
}
return BindObject(targetType, objType, obj);
}
///
/// Bind collection.
///
/// the target param type.
/// Type of the object.
/// object to be converted into a model.
///
/// An object.
///
protected virtual object BindCollection(Type targetType, Type objType, object obj)
{
var collection = obj as ICollection;
if (collection == null)
{
return null;
}
Type genericType = null;
// Make sure it has a generic type
if (targetType.GetTypeInfo().IsGenericType)
{
genericType = targetType.GetGenericArguments().FirstOrDefault();
}
else
{
var ienumerable = targetType.GetInterfaces().Where(i => i.GetTypeInfo().IsGenericType).FirstOrDefault(i => i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
genericType = ienumerable == null ? null : ienumerable.GetGenericArguments().FirstOrDefault();
}
if (genericType == null)
{
// If we don't have a generic type then just use object
genericType = typeof(object);
}
var modelType = typeof(List<>).MakeGenericType(genericType);
var model = (IList)Activator.CreateInstance(modelType);
var list = (IList