简体   繁体   中英

Accessing inner type of ICollection<SomeInnerClass> through reflection in c#

I'm attempting to set a property on an object using reflection. The property is an ICollection - if the Collection has not been instantiated, I want to get that done. My problems is that I'm having issues getting the inner type of the ICollection

This is my class

public class Report(){
    public virtual ICollection<Officer> OfficerCollection { get; set; }
}

I'm trying to access the 'Officer' class defined below through reflection

public class Officer(){
    public string Name{ get; set; }
}

Code snippet

Report report = new Report()

PropertyInfo propertyInfo = report.GetType().GetProperty("OfficerCollection");
object entity = propertyInfo.GetValue(report, null);
if (entity == null)
{
    //How do I go about creating a new List<Officer> here?
}

Give this a whirl:

Report report = new Report();

PropertyInfo propertyInfo = report.GetType().GetProperty("Officer");
object entity = propertyInfo.GetValue(report, null);
if (entity == null)
{
    Type type = propertyInfo.PropertyType.GetGenericArguments()[0];
    Type listType = typeof(List<>).MakeGenericType(type);

    var instance = Activator.CreateInstance(listType);

    propertyInfo.SetValue(...);
}

First of all you have to get the of Officer property:

var propertyType = propertyInfo.PropertyType;

Then you to extract generic type parameter:

var genericType = propertyType.GetGenericArguments()[0];

After that invoke create a generic list:

var listType = typeof(List<>).MakeGenericType(genericType);

Finally create a new instance of generic list:

var listInstance = Activator.CreateInstance(listType);

and... Have fun ;)

EDIT:

It's nice to play sometimes with reflection, but I recommend you to do it this way:

public class Report()
{
    private ICollection<Officer> officers;

    public virtual ICollection<Officer> Officer 
    {
        get
        {
            if(officers == null)
                officers = new List<Officer>();

            return officers;
        }
        set { officers = value; }
    }
}

Ignoring the issue that this whole design sounds terrible, I'll try to answer your question. You can find the type of the property with Type type = ...GetProperty(...).PropertyType . If the type was a concrete type - instead of an interface as it currently is - you could then use System.Activator.CreateInstance(type, null) - where null means no constructor arguments - to create an instance of this concrete type. Given that your property type is actually an interface, you don't know whether you should be creating a list, array, collection or any other type that would satisfy this type. You would then need to use SetValue to assign the instance to the property, but of course we're not able to get this far.

You should take this information to reevaluate your design to not depend on reflection, and instead use generic parameterization (look at the new() constraint) and lazy initialization of properties (if you think that makes sense - we're not mind readers.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM