2016-12-01 2 views
8

я прочитал тип из загруженных сборок, например:Отражение - Вызов конструктора с параметрами

var someType = loadedAssemblies 
      .Where(a => a != null && a.FullName.StartsWith("MY.")) 
      .SelectMany(a => a.GetTypes()) 
      .Distinct() 
      .ToArray()[0]; 

Если counstructor имеет параметры, я могу читать их:

ParameterInfo[] parameters = classType.GetConstructors()[0].GetParameters(); 

Я хотел бы вызвать конструктор по умолчанию значения параметра или если параметр является перечислением, с первым значением перечисления. Если имеется только один параметр, и это перечисление, это работает так:

object curObject = Activator.CreateInstance(classType, new object[] { parameters[0].ParameterType.GetEnumValues().GetValue(0) }); 

Как я могу это сделать, когда есть несколько параметров? мне нужно создать объект для чтения свойства:

var propertyInfo = someType.GetProperty("EntityType"); 
string entityType = propertyInfo.GetValue(curObject, null).ToString(); 

ответ

5

Ну, вы можете создать свой собственный завод, и написать метод, который проверяет, конструкторы типа с параметрами по умолчанию:

public static class MyFactory 
{ 
    public static T MyCreateInstance<T>() 
     where T : class 
    { 
     return (T) MyCreateInstance(typeof (T)); 
    } 

    public static object MyCreateInstance(Type type) 
    { 
     var ctor = type 
      .GetConstructors() 
      .FirstOrDefault(c => c.GetParameters().Length > 0); 

     return ctor != null 
      ? ctor.Invoke 
       (ctor.GetParameters() 
        .Select(p => 
         p.HasDefaultValue? p.DefaultValue : 
         p.ParameterType.IsValueType && Nullable.GetUnderlyingType(p.ParameterType) == null 
          ? Activator.CreateInstance(p.ParameterType) 
          : null 
        ).ToArray() 
       ) 
      : Activator.CreateInstance(type); 
    } 
} 

И тогда вы можете использовать этот метод:

var classType = loadedAssemblies 
      .Where(a => a != null && a.FullName.StartsWith("MY.")) 
      .SelectMany(a => a.GetTypes()) 
      .Distinct() 
      .ToArray()[0]; 

var curObject = MyFactory.MyCreateInstance(classType); 

// This will return an array of values 

object[] values = classType 
       .GetFields() 
       .Select(f => f.GetValue(curObject)) 
       .ToArray(); 

P.S. Вот DotNet fiddle example.

Update:

Код меняется в зависимости от сценария вы работаете. Теперь у нас есть два метода: один возвращает объект, а другой - преобразовать его в тип T.

Я также обновил DotnetFiddle, пожалуйста, проверьте его.

+0

Привет, Fabjan, спасибо за это решение. Есть одна проблема. У меня есть только classType, который я читаю во время выполнения. Я не знаю имя объекта (класса) во время компиляции. Ваш код: var curObject = MyFactory.MyCreateInstance (classType); не работает с ключевым словом объекта. – Simon

+0

Я обновил свой ответ, а также пример кода на DotNetfiddle – Fabjan

+0

Спасибо, он отлично работает.Знаете ли вы разницу между конструктором.Invoke vs Activator.CreateInstance? – Simon

2

Вы можете сделать вспомогательный метод для получения значения типа по умолчанию:

private static object GetDefaultValue(Type type) 
{ 
    if (type.IsEnum) return type.GetEnumValues().GetValue(0); 
    if (type.IsValueType) return Activator.CreateInstance(type); 
    return null; 
} 

Затем, вы можете получить значение параметров по умолчанию:

var parameters = constructor.GetParameters() 
          .Select(p => GetDefaultValue(p.ParameterType)) 
          .ToArray(); 

И вызвать ConstructorInfo, чтобы получить экземпляр:

var obj = constructor.Invoke(parameters); 

Если параметры конструктора имеют значения по умолчанию, и вы хотите использовать их, вы можете сделать что-то вроде этого:

var parameters = constructor 
    .GetParameters() 
    .Select(p => p.HasDefaultValue ? p.RawDefaultValue : GetDefaultValue(p.ParameterType)) 
    .ToArray(); 
+0

Артуро, в чем разница конструктора.Invoke vs Activator.CreateInstance? Можете ли вы сделать то же самое с Activator.CreateInstance? – Simon

+0

@Simon: 'Constructor.Invoke' непосредственно вызывает этот конструктор. 'Activator.CreateInstance' создает экземпляр, который ищет конструктор, который наилучшим образом соответствует указанным параметрам. –

Смежные вопросы