Work with unknown types



  • We need to work with the list, build and fill. Like a list.

    List<Animal<T>>;
    

    Instead of T, there is an objective valueType Type, which was transferred from outside. Build the final type.

    var animalGenType= typeof(Animal<>).MakeGenericType(valueType);
    var listType = typeof(List<>).MakeGenericType(animalGenType);
    

    Next, we can create these types of objects.

    var list = Activator.CreateInstance(listType);
    var animal= Activator.CreateInstance(animalGenType);
    

    But how do you work with that? The facilities created have the type of Object and we cannot lead them to the right type (we don't have T). And without that, how to fill the animal and then add it to the list.

    UPD: added an example of the method. He's taking the type targetPetType already in existence, so there's nowhere to go.

    public object ParsePets(IEnumerable<string> lines, Type targetPetType){
        var animalGenType= typeof(Animal<>).MakeGenericType(valueType);
        var listType = typeof(List<>).MakeGenericType(animalGenType);
    
    var result = Activator.CreateInstance(listType);         
    
    foreach(var line in lines){             
       var pet= Activator.CreateInstance(animalGenType);   
       //заполняем pet данными из line
       ...
       // добавляем в список
       ...      
    }                                       
    return result;  
    

    }

    Only reflexia?



  • Establish a common function:

    static IList<Animal<T>> ParsePetsImpl<T>(IEnumerable<string> lines) {
      // реализация
      // тут у нас есть тип T
    }
    

    This function can now be reflexed:

    public object ParsePets(IEnumerable<string> lines, Type targetPetType) {
      var method = GetType().GetMethod("ParsePetsImpl", BindingFlags.Static | BindingFlags.NonPublic);
      return method.MakeGenericMethod(targetPetType).Invoke(null, new object[] { lines });
    }
    

    If such challenges are often envisaged, it would be better to simulate the spindle dynamically:

    private static Func<IEnumerable<string>, object> MakeParsePetsImpl(Type targetPetType) {
      var method = GetType().GetMethod("ParsePetsImpl", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(targetPetType);
      var p = Expression.Parameter(typeof(IEnumerable<string>));
      var body = Expression.Call(method, null, p);
      return Expression.Lambda<Func<IEnumerable<string>, object>>(body, p).Compile();
    }
    private static ConcurrentDictionary<Type, Func<IEnumerable<string>, object>> parsePetsImpls = new ConcurrentDictionary<Type, Func<IEnumerable<string>, object>>();
    public object ParsePets(IEnumerable<string> lines, Type targetPetType) {
       return parsePetsImpls.GetOrAdd(targetPetType, MakeParsePetsImpl)(lines);
    }
    



Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2