278 lines
8.4 KiB
C#
278 lines
8.4 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using JD.Kernel.Classes;
|
|
using JD.Reflection.Attributes;
|
|
using JD.Reflection.MefImplementations.Model;
|
|
using JD.Reflection.MefImplementations.Model.Internal;
|
|
|
|
namespace JD.Reflection.MefImplementations.Composition
|
|
{
|
|
internal class ImportEngine
|
|
{
|
|
#region Variables
|
|
|
|
private readonly object m_part;
|
|
private readonly ImportDefinition m_import;
|
|
private readonly ImportType m_importType;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public ImportEngine(object part, ImportDefinition import, ImportType importType)
|
|
{
|
|
m_part = part;
|
|
m_importType = importType;
|
|
m_import = import;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
private ValueMemberInfo ImportingMember
|
|
{
|
|
get { return m_importType.ImportingMember; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
public void ApplyExportedValues(IEnumerable<ExportedValue> exportedValues)
|
|
{
|
|
switch (m_import.Cardinality)
|
|
{
|
|
case ImportCardinality.ZeroOrMore:
|
|
ApplyList(exportedValues.Select(e => e.Value));
|
|
break;
|
|
|
|
case ImportCardinality.ZeroOrOne:
|
|
case ImportCardinality.ExactlyOne:
|
|
if (exportedValues.Any())
|
|
{
|
|
SetValue(exportedValues.Single().Value);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private void SetValue(object value)
|
|
{
|
|
ThrowCompositionExceptionIf(!ImportingMember.CanRead, "Cannot set import property {0} on {1} because it is read-only", ImportingMember.Name, m_part.GetType().FullName);
|
|
ImportingMember.SetValue(m_part, value);
|
|
}
|
|
|
|
private void ApplyList(IEnumerable<object> exportedValues)
|
|
{
|
|
if (!ImportingMember.IsReadOnly && m_importType.IsAssignableCollectionType)
|
|
{
|
|
SetArray(exportedValues, m_importType.ElementType);
|
|
return;
|
|
}
|
|
|
|
ICollection<object> collection = GetCollectionWrapper();
|
|
ThrowCompositionExceptionIf(collection == null || collection.IsReadOnly, "Cannot populate the collection {0} in {1} because it does not implement ICollection<T> or is read-only. If the collection is not IEnumerable<T> or T[], it must implement ICollection<T> and be pre-initialized or be writable with a default constructor.", ImportingMember.Name, m_part.GetType().FullName);
|
|
PopulateCollection(collection, exportedValues);
|
|
}
|
|
|
|
private void SetArray(IEnumerable<object> exportedValues, Type elementType)
|
|
{
|
|
var values = exportedValues.ToList();
|
|
var array = Array.CreateInstance(elementType, values.Count);
|
|
|
|
for (int i = 0; i < values.Count; i++)
|
|
{
|
|
array.SetValue(values[i], i);
|
|
}
|
|
|
|
SetValue(array);
|
|
}
|
|
|
|
private ICollection<object> GetCollectionWrapper()
|
|
{
|
|
object collectionObject = null;
|
|
|
|
if (ImportingMember.CanRead)
|
|
{
|
|
collectionObject = ImportingMember.GetValue(m_part);
|
|
}
|
|
|
|
if (collectionObject == null)
|
|
{
|
|
ConstructorInfo constructor = ImportingMember.ValueType.GetConstructor(Type.EmptyTypes);
|
|
|
|
// If it contains a default public constructor, create a new instance.
|
|
if (constructor != null)
|
|
{
|
|
collectionObject = constructor.Invoke(new object[0]);
|
|
SetValue(collectionObject);
|
|
}
|
|
}
|
|
|
|
ThrowCompositionExceptionIf(collectionObject == null, "Cannot populate the value of enumerable member {0} on {1} because it is null. If the collection is not IEnumerable<T> or T[], it must implement ICollection<T> and be either pre-initialized or be writable with a default constructor.", ImportingMember.Name, m_part.GetType().FullName);
|
|
|
|
return GetCollectionWrapperImpl(m_importType.ElementType, collectionObject);
|
|
}
|
|
|
|
private static ICollection<object> GetCollectionWrapperImpl(Type itemType, object collectionObject)
|
|
{
|
|
if (itemType == typeof(object))
|
|
{
|
|
return (ICollection<object>)collectionObject;
|
|
}
|
|
|
|
// Most common .Net collections implement IList as well so for those
|
|
// cases we can optimize the wrapping instead of using reflection to create
|
|
// a generic type.
|
|
if (typeof(IList).IsAssignableFrom(collectionObject.GetType()))
|
|
{
|
|
return new CollectionOfObjectList((IList)collectionObject);
|
|
}
|
|
|
|
Type collectionType = typeof(CollectionOfObject<>).MakeGenericType(itemType);
|
|
|
|
return (ICollection<object>)Activator.CreateInstance(collectionType, collectionObject);
|
|
}
|
|
|
|
private static void PopulateCollection(ICollection<object> collection, IEnumerable values)
|
|
{
|
|
collection.Clear();
|
|
|
|
foreach (object value in values)
|
|
{
|
|
collection.Add(value);
|
|
}
|
|
}
|
|
|
|
private static void ThrowCompositionExceptionIf(bool condition, string msg, params object[] args)
|
|
{
|
|
if (condition)
|
|
{
|
|
throw new CompositionException(string.Format(msg, args));
|
|
}
|
|
}
|
|
|
|
#region Inner Types
|
|
|
|
private class CollectionOfObjectList : ICollection<object>
|
|
{
|
|
private readonly IList m_list;
|
|
|
|
public CollectionOfObjectList(IList list)
|
|
{
|
|
m_list = list;
|
|
}
|
|
|
|
public void Add(object item)
|
|
{
|
|
m_list.Add(item);
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
m_list.Clear();
|
|
}
|
|
|
|
public bool Contains(object item)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public void CopyTo(object[] array, int arrayIndex)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { throw new NotSupportedException(); }
|
|
}
|
|
|
|
public bool IsReadOnly
|
|
{
|
|
get { return m_list.IsReadOnly; }
|
|
}
|
|
|
|
public bool Remove(object item)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public IEnumerator<object> GetEnumerator()
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
private class CollectionOfObject<T> : ICollection<object>
|
|
{
|
|
private readonly ICollection<T> m_collectionOfT;
|
|
|
|
public CollectionOfObject(object collectionOfT)
|
|
{
|
|
m_collectionOfT = (ICollection<T>)collectionOfT;
|
|
}
|
|
|
|
public void Add(object item)
|
|
{
|
|
m_collectionOfT.Add((T)item);
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
m_collectionOfT.Clear();
|
|
}
|
|
|
|
public bool Contains(object item)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public void CopyTo(object[] array, int arrayIndex)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { throw new NotSupportedException(); }
|
|
}
|
|
|
|
public bool IsReadOnly
|
|
{
|
|
get { return m_collectionOfT.IsReadOnly; }
|
|
}
|
|
|
|
public bool Remove(object item)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public IEnumerator<object> GetEnumerator()
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
}
|