Make call to generic class nested function - c#

I have Repository<T> where T is derrived form of BaseEntity class.
Repository<T> has IQueryable<T> Table property. I need to make a call to FirstOrDefault method in the Table property.
till now i have got to list the Repositories, but stuck making call to the method using reflection.
private IEnumerable<object> GetEnumerableRepositoryOf<T>(params object[] constructorArgs) where T : class
{
List<object> objects = new List<object>();
foreach (Type type in
Assembly.GetAssembly(typeof(T)).GetTypes()
.Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(T))))
{
objects.Add(Activator.CreateInstance(typeof(Repository<>).MakeGenericType(type), constructorArgs));
}
return objects;
}
var repoList = GetEnumerableRepositoryOf<BaseEntity>(constructorArgs);
foreach (var repo in repoList)
{
// call FirstOrDefault() here
}

So your list is Repository<X> where X is T, and the property Table is IQueryable<X>. As we are lacking type knowledge of X at compile time, reflection it is.
So get the property with reflection by using the non-generic interface, then apply cast to T, and do your FirstOrDefault.
Here's how you can do it:
foreach (var repo in repoList)
{
var firstOrNull =
(repo.GetType().GetProperty("Table").GetValue(repo) as IQueryable)
.Cast<BaseEntity>().FirstOrDefault();
}
If using entity framework (which does not support this kind of casting above):
foreach (var repo in repoList)
{
var enumerator =
(repo.GetType().GetProperty("Table").GetValue(repo) as IEnumerable)
.GetEnumerator();
var firstOrNull = (BaseEntity) (enumerator.MoveNext() ?
enumerator.Current : default(BaseEntity));
}

Related

Concatenating Lists at runtime

I am handling classes that wrap collections. For example:
public class CollA
{
public List<SomeType> Items {get;set;}
// other properties I'm not interested in
}
I am guaranteed that the collection classes will have exactly ONE property that is of List<T>
Now, I find myself with a requirement such that I may have many instances of CollA and I am asked to return a new instance of CollA where the property Items contains a union of the Items properties of the individual CollA instances. So, for example:
var A = new CollA(Items = new List<SomeType>
{
new SomeType("A"), new SomeType("B")
};
var B = new CollA(Items = new List<SomeType>
{
new SomeType("C"), new SomeType("D")
};
var result = SomeMythicalCombine(A, B);
// result.Items == { new SomeType("A"), new SomeType("B"), new SomeType("C"), new SomeType("D") }
This, if the types are all known at compile time is easy, but I need to do it with the types not being known until runtime.
I've got part of the way, I think, using reflection....
public T SomeMythicalCombine (params object[] collections)
{
var collectionType = typeof(T);
var listProperty = collectionType.GetProperties()
.Single(p=> typeof(IList).IsAssignableFrom(p.PropertyType));
var listPropertyName = listProperty.Name;
var result = Activator.CreateInstance(collectionType);
var innerType = listProperty.PropertyType.GenericTypeArguments[0];
var listType = typeof(List<>).MakeGenericType(innerType);
var list = Activator.CreateInstance(listType);
foreach(var collection in collections)
{
var listValues = collection.GetType().GetProperty(listPropertyName).GetValue(collection);
// listItems is an object here and I need to find a way of casting it
// to something I can iterate over so I can call (list as IList).Add(something)
}
// Then, I think, all I need to do is set the appropriate property on the
// the result item
result.GetType().GetProperty(listPropertyName).SetValue(result, list);
return result as T;
}
Can anyone fill in the gap in my thinking, please?
So basically if you know the type at compile time, you can do this:
var result = new CollA { Items = new[] { A, B }.SelectMany(c => c.Items).ToList() };
If you can require all your collection wrappers to implement an interface, it should be pretty simple to extract this into a generic method.
public interface ICollectionWrapper<T> { List<T> Items { get; set; } }
T SomeMythicalCombine<T, T2>(params T[] wrappers) where T : ICollectionWrapper<T2>, new()
{
return new T() { Items = wrappers.SelectMany(w => w.Items).ToList() };
}
That presupposes you can call the method with the right generic parameter. If your calling code knows the types of the collections you're dealing with, you can do this:
var result = SomeMythicalCombine(A, B);
But honestly if your calling code knows that, you might be better off using the first code snippet: it's concise and clear enough. Assuming you literally have a collection of objects that you just happen to know will all have the same run-time type, you should be able to use a little reflection to get that type and invoke the helper method with the right generic parameters. It's not ideal, but it might be faster/simpler than writing the entire method to work using reflection.
you can do this : var combined = A.Items.Concat(B.Items).
However, if the property is a part of interface or base class implementation, then you can target the implementation instead something like this :
public IList<TResult> SomeMythicalCombine<TResult>(params IInterface[] collection) // use interface or base class
{
// assuming that all collection would have the same element type.
}
if it is not a part of other implementations, then you can implement an interface and apply it to all classes, this would be an insurance that this collection will always be there as long as the class implements the interface.
if it's hard to achieve that, then you can and you see that reflection is your best option, you can use something like this :
// assuming all collections have the same property of type List<TResult> type.
// if they're different, then return an object instead. and change List<TResult> to IList
public IEnumerable<TResult> CombineLists<T, TResult>(params T[] instances)
where T : class
{
if (instances?.Any() == false) yield break;
foreach(var obj in instances)
{
if (obj == null) continue;
var list = obj.GetType()
.GetProperties()
.FirstOrDefault(p => typeof(List<TResult>).IsAssignableFrom(p.PropertyType))
?.GetValue(obj) as List<TResult>;
if (list?.Count == 0) continue;
foreach (var item in list)
yield return item;
}
}
usage :
var combined = CombineLists<CollA, string>(A, B);

Add items to any object of ICollection<T> using reflection

I'm trying to support mapping to/from any kind of collection that implements ICollection<T> via reflection, because ICollection<T> requires implementation of the Add method.
This works fine for most common collection types, but fails for edge cases like LinkedList<T> where the Add method is hidden and can only be called by casting the LinkedList<T> to ICollection<T>.
However it's not possible to convert to ICollection<> because it is not covariant.
The other option I was considering was searching for both implicit and explicit implementations of Add, but I don't see any information on how to do this when the interface is generic?
What would be the correct approach to take?
Updated to show code snippet where I'm reflecting from xml to object mapping.
private object CollectionXmlNodeListToObject(
XmlNodeList nodeList, System.Type collectionType)
{
// this is not possible because ICollection<> is not covariant
object collection = Convert.ChangeType(
CreateInstanceOfType(collectionType), ICollection<>);
Type containedType = collectionType.GetTypeInfo().GenericTypeArguments[0];
foreach (XmlNode node in nodeList)
{
object value = CreateInstanceOfType(containedType);
if (containedType.IsClass && MetaDataCache.Contains(containedType))
value = ToObject(value, node, node.Name);
else
value = node.InnerText;
// this throws NullReferenceException when the type is LinkedList,
// because this is explicitly implemented in LinkedList
collectionType.GetMethod("Add")
.Invoke(collection, new[] { value });
}
return collection;
}
I am writing a small framework to map from object to xml using class and property attributes. So I cannot use generics because all of this is being done at runtime.
I initially was checking for IEnumerable before, but ran into other oddities with it (strings implement IEnumerable and are immutable) that I decided it was safest to stick to ICollection<>
With explicit interface implementation, the object has all the interface methods, but the object's Type does not.
So here's how to add an item to a LinkedList<T>, or any ICollection<T> through reflection:
var ll = new LinkedList<int>();
var t = typeof(int);
var colType = typeof(ICollection<>).MakeGenericType(t);
var addMethod = colType.GetMethod("Add");
addMethod.Invoke(ll, new object[] { 1 });
This functionality is met at compile-time using the Cast<T>() method. You just need a run-time version, which is pretty straightforward:
static public object LateCast(this ICollection items, Type itemType)
{
var methodDefintionForCast = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Cast")
.Select(mi => mi.GetGenericMethodDefinition())
.Single(gmd => gmd != null && gmd.GetGenericArguments().Length == 1);
var method = methodDefintionForCast.MakeGenericMethod(new Type[] { itemType });
return method.Invoke(null, new[] { items });
}
Now you can take any non-generic collection and make it generic at run-time. For example, these two are equivalent:
var list = nodeList.Cast<XmlNode>();
object list = nodeList.LateCast(typeof(XmlNode));
And you can convert a whole collection with this:
static public IEnumerable ConvertToGeneric(this ICollection source, Type collectionType)
{
return source.LateCast(collectionType.GetGenericArguments()[0]) as IEnumerable;
}
object list = nodeList.ConvertToGeneric(nodeList, typeof(ICollection<XmlNode>));
This solution works with linked lists as well as all the other collection types.
See my working example on DotNetFiddle
Pretty much all .NET collections take an IEnumerable<T> as the constructor, so you could make use of that:
private static object CollectionXmlNodeListToObject(System.Type collectionType)
{
// T
Type containedType = collectionType.GetTypeInfo().GenericTypeArguments[0];
// List<T>
Type interimListType = typeof(List<>).MakeGenericType(containedType);
// IEnumerable<T>
Type ienumerableType = typeof(IEnumerable<>).MakeGenericType(containedType);
IList interimList = Activator.CreateInstance(interimListType) as IList;
interimList.Add(null);
interimList.Add(null);
interimList.Add(null);
interimList.Add(null);
// If we can directly assign the interim list, do so
if (collectionType == interimListType || collectionType.IsAssignableFrom(interimListType))
{
return interimList;
}
// Try to get the IEnumerable<T> constructor and use that to construct the collection object
var constructor = collectionType.GetConstructor(new Type[] { ienumerableType });
if (constructor != null)
{
return constructor.Invoke(new object[] { interimList });
}
else
{
throw new NotImplementedException();
}
}
Try it online
Obviously you could optimise this by moving the list population to another method, and then maybe use your existing method as far as you can, and then use this where you can't.

C# - Make a generic foreach method that accepts any type?

Im busy updating an entity using entity framework and web api (on the PUT method of the controller). For each collection property on the updated object, I loop through and check if each item exists in the collection on the existing object or not. If not, I add it.
The trouble is I have a lot of collections on the object and I find myself repeating the following code many times over.
Is there a way for me to wrap this into a generic method and pass that method the 2 collections to compare? Maybe by specifying the name of the property to check and primary key? How would I be able to specify the type for the foreach loop for example?
foreach (HBGender gender in updated.HBGenders)
{
HBGender _gender = existing.HBGenders.FirstOrDefault(o => o.GenderID == gender.GenderID);
if (_gender == null)
{
//do some stuff here like attach and add
}
}
return existing; //return the modified object
Thanks in advance. I hope this makes sense.
In its simplest form you could write an extension method as such:
public static class IEnumerableExtensionMethods
{
public static ICollection<T> ForEachAndAdd<T>(this IEnumerable<T> self,
ICollection<T> other,
Func<T, T, bool> predicate) where T : class
{
foreach(var h1 in self)
{
if(other.FirstOrDefault(h2 => predicate(h1, h2)) == null)
other.Add(h1);
}
return other;
}
}
Usage:
List<HBGender> updated = new List<HBGender>();
List<HBGender> existing = new List<HBGender<();
return updated.ForEachAndAdd(existing, (h1, h2) => h1.Gender == h2.Gender);
Note that if there is extra logic needed during an add, you could add an additonal Action<T> parameter to do so.
I don't know what you are trying to do, but you can play with this example:
List<object> a = new List<object>();
a.Add("awgf");
a.Add('v');
a.Add(4);
foreach (object b in a)
{
Type type = b.GetType().//Select more usefull
Convert.ChangeType(object,type);
}
Just pass your existing check function, as an extra parameter
public List<Class1> Find(List<Class1> updated, List<Class1> existing, Func<Class1, bool> predicate)
{
foreach (Class1 gender in updated)
{
Class1 _gender = existing.FirstOrDefault(predicate); //predicate for quoted example will be o => o.GenderID == gender.GenderID
if (_gender == null)
{
//do some stuff here like attach and add
}
}
return existing;
}

Casting List<object> to List<T> at runtime

I 'm trying to build a DI container and I 've stumbled on to the following problem: I have a method that retrieves a list of registered instances for a given type and I want to use that to inject IEnumerable<T> properties in a given object. An example of what I am trying to achieve would be the following:
class A { public IList<IExample> Objects { get; set; } }
class B: IExample {}
class C: IExample {}
Container.Register<IExample>(new B());
Container.Register<IExample>(new C());
var obj = new A();
Container.Inject(A);
Debug.Assert(A.Objects != null && A.Objects.Count == 2);
My Retrieve method returns an IList<object>, mainly because I have no type information at that moment, so I am attempting to convert that list into a List<T> at injection time. Here is a succint form of the methods doing the work:
public virtual IList<object> Retrieve(Type type)
{
var instances = Registry[type];
foreach(var instance in instances)
Inject(type, instance); // omitted
return instances;
}
public virtual void Inject<T>(T instance)
{
var properties = typeof (T).GetProperties();
foreach (var propertyInfo in properties)
{
var propertyType = propertyInfo.PropertyType;
if (!IsIEnumerable(propertyType)) continue;
var genericType = propertyType.GetGenericArguments()[0];
propertyInfo.SetValue(instance,
GetListType(genericType, Retrieve(genericType)), null);
}
}
protected virtual object GetListType(Type type, IEnumerable<object> items)
{
return items.Select(item => Convert.ChangeType(item, type)).ToList();
}
The code returns the error: System.InvalidCastException : Object must implement IConvertible. Sadly, I don't know how to proceed from here. Perhaps I am doing this all wrong. I 've thought of using generics or injecting multiple properties by hand, but I'd really like to not have to do that.
Thanks in advance for any help or ideas.
You could create a generic list like this:
public virtual IList Retrieve(Type type)
{
// ...
listType = typeof(List<>).MakeGenericType(new Type[] { type });
IList list = (IList)Activator.CreateInstance(listType);
// ...
return list
}
this list can be casted to IList<T>, because it is one.
You could consider to use IEnumerable and Cast<T>, but then you don't have an instance of a list. I don'^t know how important it is to have one.

C# Covariance issue

I had a linq-to-sql generated domain entity that I cast to the proper interface like so:
public IEnumerable<IApplication> GetApplications()
{
using (var dc = new LqDev202DataContext())
{
return dc.ZApplications.Cast<IApplication>().ToList();
}
}
However I renamed the linq-to-sql table without touching my partial class and the code still compiled.
The list had the right amount of elements, but they were all null.
Do I need to write a helper method to make sure this will work, or is there a compile time safe simple built-in way to do this in .net 3.5?
You can also use this to do casting with conversions if needed:
public static IEnumerable<TDest> CastAll<TItem, TDest>(this IEnumerable<TItem> items)
{
var p = Expression.Parameter(typeof(TItem), "i");
var c = Expression.Convert(p, typeof(TDest));
var ex = Expression.Lambda<Func<TItem, TDest>>(c, p).Compile();
foreach (var item in items)
{
yield return ex(item);
}
}
From http://adventuresdotnet.blogspot.com/2010/06/better-more-type-safe-alternative-to.html

Categories