2016-12-01 10 views
8

I-Typen von geladenen Baugruppen zum Beispiel lesen:Reflection - Aufruf Konstruktor mit Parametern

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

Wenn counstructor Parameter hat, ich kann sie lesen:

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

Ich mag würde Konstruktor mit Standard anrufen Parameterwerte oder wenn der Parameter enum ist, mit dem ersten Enum-Wert. Wenn nur ein Parameter ist, und es ist Enum, funktioniert es wie folgt aus:

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

Wie kann ich dies tun, wenn es mehr Parameter sind? Ich brauche Objekt zu erstellen, um die Eigenschaft zu lesen:

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

Antwort

5

Nun, können Sie Ihre eigenen Fabrik erstellen, und schreiben Verfahren, dass die Kontrollen Typ des Konstrukteurs mit ihren Standardparameter:

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); 
    } 
} 

Und dann können Sie diese Methode verwenden:

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. Hier ist ein DotNet fiddle example.

Update:

Der Code geändert wird nach Szenario mit Ihnen zusammenarbeiten. Jetzt haben wir zwei Methoden, Eins gibt Objekt zurück, und ein anderes, das es in Typ T konvertieren kann.

Ich habe auch die DotnetFiddle aktualisiert, überprüfen Sie es bitte.

+0

Hallo Fabjan, danke für diese Lösung. Es gibt ein Problem. Ich habe nur classType, die ich zur Laufzeit gelesen habe. Ich weiß nicht für den Objekt (Klasse) Namen zur Kompilierzeit. Ihr Code: var curObject = MyFactory.MyCreateInstance (classType); funktioniert nicht mit Objektschlüsselwort. – Simon

+0

Ich habe meine Antwort sowie Codebeispiel auf DotNetfiddle – Fabjan

+0

aktualisiert Vielen Dank, es funktioniert perfekt.Kennen Sie den Unterschied zwischen constructor.Invoke vs Activator.CreateInstance? – Simon

2

Sie können eine Hilfsmethode machen Standardwert eines Typs zu erhalten:

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

Dann Standardwerte der Parameter zu erreichen:

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

und rufen Sie den ConstructorInfo die Instanz zu erhalten:

var obj = constructor.Invoke(parameters); 

Wenn die Konstrukteurs-Parameter Standardwerte haben, und Sie wollen, dass sie verwenden, können Sie etwas tun:

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

Arturo, was ist der Unterschied von constructor.Invoke vs Activator.CreateInstance? Können Sie das gleiche mit Activator.CreateInstance tun? – Simon

+0

@Simon: 'Constructor.Invoke' ruft direkt diesen Konstruktor auf. 'Activator.CreateInstance' erstellt eine Instanz, die den Konstruktor findet, der den angegebenen Parametern am besten entspricht. –

Verwandte Themen