I have this helper method that is designed to transfer collection items from one collection object instance to another. It works, but I have recently ran into an issue where a particular collection implements at different points IEnumerable. At one level as IEnumerable> and at another IEnumerable. In my code below, the declaration of secondaryCollection causes it to use the IEnumerable instance type versus the collectionType declaration finds it as the base ICollection> type so that I can invoke the Add() and Remove(). With this type mismatch though the Add() and Remove() method invocations fail. I think if I can figure out how to declare secondaryCollection as type IEnumerable where 'object' is of type KeyValuePair and not of just the type TValue that this should work without the type mismatch exception (it's actually an argument exception for the Add(), Remove() methods). The problem is this is all done in reflection and the types are unknown. How can I do this?
Here's the current method code:
public void MergeCollection(FieldInfo primaryMember, object primaryObject, FieldInfo secondaryMember, object secondaryObject)
{
if (primaryMember == null)
throw new ArgumentNullException("primaryMember");
if (primaryObject == null)
throw new ArgumentNullException("primaryObject");
if (secondaryMember == null)
throw new ArgumentNullException("secondaryMember");
if (secondaryObject == null)
throw new ArgumentNullException("secondaryObject");
//Get the collection type and validate
Type genericType = typeof(ICollection<>);
Type collectionType = primaryMember.FieldType.GetBaseTypes().FirstOrDefault(t => t.IsGenericType && t.GetGenericArguments().Length == 1 && t == genericType.MakeGenericType(t.GetGenericArguments()));
if (!collectionType.IsAssignableFrom(secondaryMember.FieldType))
throw new InvalidOperationException("Primary and secondary collection types do not match.");
Type collectionParamType = collectionType.GetGenericArguments()[0];
//Get the collection invocable methods
MethodInfo add = collectionType.GetMethod("Add", new Type[] { collectionParamType });
MethodInfo remove = collectionType.GetMethod("Remove", new Type[] { collectionParamType });
//Declare the collections
object primaryCollectionObject = primaryMember.GetValue(primaryObject);
object secondaryCollectionObject = secondaryMember.GetValue(secondaryObject);
Type genericEnumerableType = typeof(IEnumerable<>);
Type enumerableType = primaryMember.FieldType.GetBaseTypes().FirstOrDefault(t => t.IsGenericType && t.GetGenericArguments().Length == 1 && t == genericEnumerableType.MakeGenericType(t.GetGenericArguments()));
IEnumerable<object> secondaryCollection = ((IEnumerable)secondaryCollectionObject).Cast<object>();
//Transfer the items
int noItems = secondaryCollection.Count();
// int noItems = (int)count.GetValue(secondaryCollectionObject);
for (int i = 0; i < noItems; i++)
{
try
{
add.Invoke(primaryCollectionObject, new object[] { secondaryCollection.ElementAt(0) });
remove.Invoke(secondaryCollectionObject, new object[] { secondaryCollection.ElementAt(0) });
}
catch (ArgumentException ex)
{
//The argument exception can be captured here
}
}
}
Aucun commentaire:
Enregistrer un commentaire