I was using 3rd-party package to a .Net cms, kind of ORM from internal data representation to a POCO. To get it worked I needed to take it's source code from GitHub to debug and see what is wrong. I've found that there is reflection MethodInfo.Invoke call to a method that uses yield return. The return from this method is supposed to be assigned to a POCO's property with property.SetValue(). And this very call returned null that, being set to a property, caused invalid result of mapping.
I changed method's logic a bit to compose IEnumerable<> first and then return it as it is with ordinary return, no yield - then everything started working properly.
My question is - since this package was downloaded and used by other people so it is considered to be working, putting aside my source code change - perhaps there is some approach to deal with Invoked methods that return with yield? I know that yield returns an ienumerator (state machine) that is to be used in foreach-like loops over some IEnumerable but it is for direct IEnumerable generator method call, it was the first time when I saw reflection-call of such method. Thanks.
UPDATE: Thanks @GeorgeVovos. The plugin is https://github.com/AliSheikhTaheri/Archetype-Mapper. The code that caused problem is:
Calling part:
public void SetPropertyValue<T>(object fromObject, PropertyInfo property, T model, IUmbracoMapper mapper) { var fieldsets = GetArchetypeModel(fromObject); if (fieldsets != null) { var type = property.PropertyType.GetGenericArguments()[0]; var method = GetType().GetMethod("GetItems", BindingFlags.NonPublic | BindingFlags.Instance); var genericMethod = method.MakeGenericMethod(type); var items = genericMethod.Invoke(this, new object[] { fieldsets, mapper }); property.SetValue(model, items); } }
Method:
private IEnumerable<T> GetItems<T>(IEnumerable<ArchetypeFieldsetModel> fieldsets, IUmbracoMapper mapper) { foreach (var fieldset in fieldsets) { // Instantiate the T var instance = (T)Activator.CreateInstance(typeof(T)); // make a dictionary of property alias and value var dictionary = fieldset.Properties.ToDictionary(property => FirstToUpper(property.Alias), property => property.Value); // If fieldset name is the same as instance type then lets map it to the instance if (instance.GetType().Name.ToLower() == fieldset.Alias.ToLower()) { mapper.Map(dictionary, (object)instance); } else // if not then lets find a property with the same name as fieldset name { var property = instance.GetType().GetProperties().FirstOrDefault(x => x.Name.ToLower() == fieldset.Alias.ToLower()); if (property != null) { var propertyClass = Activator.CreateInstance(property.PropertyType); mapper.Map(dictionary, propertyClass); var propertyInfo = instance.GetType().GetProperty(property.Name); propertyInfo.SetValue(instance, Convert.ChangeType(propertyClass, propertyInfo.PropertyType)); } } yield return instance; } }
I understood your answer. Looks like when I started to use the plugin my code (model) had incorrectly defined properties decorated with attribute for which plugin code maps data from CMS. As I understood original plugin code provides lazy data obtaining while my changes made it eager. But if I were define properties as ienumerables at first I would not come to the problem.
Thank a lot!