Ruft den Eigenschaftswert aus der Zeichenfolge mithilfe der Reflektion in C # ab

928

Ich versuche, die Datentransformation mithilfe des Reflection 1- Beispiels in meinem Code zu implementieren .

Die GetSourceValueFunktion hat einen Schalter, der verschiedene Typen vergleicht, aber ich möchte diese Typen und Eigenschaften entfernen und GetSourceValueden Wert der Eigenschaft nur mit einer einzigen Zeichenfolge als Parameter abrufen. Ich möchte eine Klasse und eine Eigenschaft in der Zeichenfolge übergeben und den Wert der Eigenschaft auflösen.

Ist das möglich?

1 Webarchivversion des ursprünglichen Blogposts

pedrofernandes
quelle

Antworten:

1793
 public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }

Natürlich möchten Sie Validierung und so weiter hinzufügen, aber das ist der Kern davon.

Ed S.
quelle
8
Schön und einfach! Ich würde es aber generisch machen:public static T GetPropertyValue<T>(object obj, string propName) { return (T)obj.GetType().GetProperty(propName).GetValue(obj, null); }
Ohad Schneider
2
Eine Optimierung kann das Risiko einer Nullausnahme wie folgt beseitigen: " src.GetType().GetProperty(propName)?.GetValue(src, null);";).
shA.t
8
@ shA.t: Ich denke das ist eine schlechte Idee. Wie unterscheidet man zwischen einem Nullwert einer vorhandenen Eigenschaft oder gar keiner Eigenschaft? Ich würde viel lieber sofort wissen, dass ich einen schlechten Immobiliennamen eingeschickt habe. Dies ist kein Produktionscode, aber eine bessere Verbesserung wäre, eine spezifischere Ausnahme auszulösen (z. B. auf Null prüfen GetPropertyund auslösen PropertyNotFoundExceptionoder etwas, wenn Null).
Ed S.
210

Wie wäre es mit so etwas:

public static Object GetPropValue(this Object obj, String name) {
    foreach (String part in name.Split('.')) {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        PropertyInfo info = type.GetProperty(part);
        if (info == null) { return null; }

        obj = info.GetValue(obj, null);
    }
    return obj;
}

public static T GetPropValue<T>(this Object obj, String name) {
    Object retval = GetPropValue(obj, name);
    if (retval == null) { return default(T); }

    // throws InvalidCastException if types are incompatible
    return (T) retval;
}

Auf diese Weise können Sie mit einer einzelnen Zeichenfolge wie folgt in Eigenschaften absteigen:

DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");

Sie können diese Methoden entweder als statische Methoden oder als Erweiterungen verwenden.

jheddings
quelle
3
@FredJand froh, dass du darauf gestoßen bist! Es ist immer wieder überraschend, wenn diese alten Beiträge auftauchen. Es war ein wenig vage, also fügte ich ein bisschen Text hinzu, um es zu erklären. Ich habe auch auf diese als Erweiterungsmethoden umgestellt und ein generisches Formular hinzugefügt, also habe ich es hier hinzugefügt.
Hochzeiten
Warum ist der Nullwächter im Vorfeld und nicht oben?
Santhos
4
@Santhos Da 'obj' im Hauptteil der foreach-Schleife neu definiert wird, wird es bei jeder Iteration überprüft.
jheddings
Nützlich, aber in dem Fall, dass eine der verschachtelten Eigenschaften ausgeblendet sein könnte (unter Verwendung des Modifikators 'neu'), wird eine Ausnahme zum Suchen doppelter Eigenschaften ausgelöst. Es wäre übersichtlicher, den letzten Eigenschaftstyp zu verfolgen und PropertyInfo.PropertyTypeanstelle von obj.GetType()verschachtelten Eigenschaften zu verwenden, genau wie dies der Zugriff auf die Eigenschaft einer verschachtelten Eigenschaft tun würde.
Nullius
Sie können den nameofAusdruck ab C # 6 wie folgt verwenden: nameof(TimeOfDay.Minutes)für den Parameter name, wenn Sie die Funktion aufrufen, um magische Zeichenfolgen zu entfernen und diesen Aufrufen Sicherheit bei der Kompilierung zu verleihen.
Ernten Sie
74

Zu jedem hinzufügen Class:

public class Foo
{
    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }

    public string Bar { get; set; }
}

Dann können Sie verwenden als:

Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];
Eduardo Cuomo
quelle
@EduardoCuomo: Ist es möglich, Reflexion damit zu verwenden, so dass Sie nicht wissen müssen, welche Mitglieder die Klasse hat?
Unser Mann in Bananen
Ist es möglich, dies zu tun, wenn "Bar" ein Objekt wäre?
big_water
@big_water die SetValueund GetValueMethoden arbeiten mit Object. Wenn Sie mit einem bestimmten Typ arbeiten müssen, sollten Sie das Ergebnis von GetValueund den Wert umwandeln, um ihn zuzuweisenSetValue
Eduardo Cuomo
Sorry @OurManinBananas, ich kann deine Frage nicht verstehen. Was möchten Sie tun?
Eduardo Cuomo
Wie heißt dieser Typ Methoden ..?
Sahan Chinthaka
45

Was ist mit der Verwendung CallByNamedes Microsoft.VisualBasicNamespace ( Microsoft.VisualBasic.dll)? Es verwendet Reflektion, um Eigenschaften, Felder und Methoden von normalen Objekten, COM-Objekten und sogar dynamischen Objekten abzurufen.

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

und dann

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();
Fredou
quelle
5
Interessanter Vorschlag, weitere Inspektion hat gezeigt, dass es sowohl Felder als auch Eigenschaften, COM-Objekte und sogar korrekt dynamische Bindungen verarbeiten kann !
IllidanS4 will Monica
Ich erhalte eine Fehlermeldung: Öffentliches Mitglied 'MyPropertyName' vom Typ 'MyType' wurde nicht gefunden.
vldmrrdjcc
30

Tolle Antwort von jheddings. Ich möchte es verbessern und die Referenzierung von aggregierten Arrays oder Sammlungen von Objekten ermöglichen, sodass propertyName property1.property2 [X] .property3 sein kann:

    public static object GetPropertyValue(object srcobj, string propertyName)
    {
        if (srcobj == null)
            return null;

        object obj = srcobj;

        // Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
        string[] propertyNameParts = propertyName.Split('.');

        foreach (string propertyNamePart in propertyNameParts)
        {
            if (obj == null)    return null;

            // propertyNamePart could contain reference to specific 
            // element (by index) inside a collection
            if (!propertyNamePart.Contains("["))
            {
                PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart);
                if (pi == null) return null;
                obj = pi.GetValue(obj, null);
            }
            else
            {   // propertyNamePart is areference to specific element 
                // (by index) inside a collection
                // like AggregatedCollection[123]
                //   get collection name and element index
                int indexStart = propertyNamePart.IndexOf("[")+1;
                string collectionPropertyName = propertyNamePart.Substring(0, indexStart-1);
                int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length-indexStart-1));
                //   get collection object
                PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName);
                if (pi == null) return null;
                object unknownCollection = pi.GetValue(obj, null);
                //   try to process the collection as array
                if (unknownCollection.GetType().IsArray)
                {
                    object[] collectionAsArray = unknownCollection as object[];
                    obj = collectionAsArray[collectionElementIndex];
                }
                else
                {
                    //   try to process the collection as IList
                    System.Collections.IList collectionAsList = unknownCollection as System.Collections.IList;
                    if (collectionAsList != null)
                    {
                        obj = collectionAsList[collectionElementIndex];
                    }
                    else
                    {
                        // ??? Unsupported collection type
                    }
                }
            }
        }

        return obj;
    }
AlexD
quelle
Was ist mit einer Liste von Listen, auf die MasterList [0] [1] zugreift?
Jesse Adam
als Array -> als Objekt [] führt ebenfalls zu einer Nullreferenzausnahme. Was für mich funktioniert (Requisite nicht die effizienteste Methode), ist, unknownCollection in IEnumerable umzuwandeln und dann ToArray () für das Ergebnis zu verwenden. Geige
Jeroen Jonkman
14

Wenn ich den Code von Ed S. verwende, bekomme ich

'ReflectionExtensions.GetProperty (Typ, Zeichenfolge)' ist aufgrund seiner Schutzstufe nicht zugänglich

Es scheint, dass GetProperty()dies in Xamarin.Forms nicht verfügbar ist. TargetFrameworkProfilebefindet sich Profile7in meiner Portable Class Library (.NET Framework 4.5, Windows 8, ASP.NET Core 1.0, Xamarin.Android, Xamarin.iOS, Xamarin.iOS Classic).

Jetzt habe ich eine funktionierende Lösung gefunden:

using System.Linq;
using System.Reflection;

public static object GetPropValue(object source, string propertyName)
{
    var property = source.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.OrdinalIgnoreCase));
    return property?.GetValue(source);
}

Quelle

testen
quelle
4
Nur eine winzige mögliche Verbesserung. Ersetzen Sie IF und next return durch: return property? .GetValue (source);
Tomino
11

In Bezug auf die Diskussion über verschachtelte Eigenschaften können Sie alle Überlegungen vermeiden, wenn Sie DataBinder.Eval Method (Object, String)Folgendes verwenden:

var value = DataBinder.Eval(DateTime.Now, "TimeOfDay.Hours");

Natürlich müssen Sie einen Verweis auf die System.WebBaugruppe hinzufügen , aber dies ist wahrscheinlich keine große Sache.

Rubens Farias
quelle
8

Die aufzurufende Methode wurde in .NET Standard (ab 1.6) geändert. Wir können auch den Null-Bedingungsoperator von C # 6 verwenden.

using System.Reflection; 
public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}
Matt Frear
quelle
1
für die Verwendung der? operator
blfuentes
4

Verwenden von PropertyInfo des System.Reflection- Namespace. Reflection wird problemlos kompiliert, unabhängig davon, auf welche Eigenschaft wir zugreifen möchten. Der Fehler tritt zur Laufzeit auf.

    public static object GetObjProperty(object obj, string property)
    {
        Type t = obj.GetType();
        PropertyInfo p = t.GetProperty("Location");
        Point location = (Point)p.GetValue(obj, null);
        return location;
    }

Es funktioniert gut, die Location-Eigenschaft eines Objekts abzurufen

Label1.Text = GetObjProperty(button1, "Location").ToString();

Wir erhalten den Ort: {X = 71, Y = 27} Auf die gleiche Weise können wir auch location.X oder location.Y zurückgeben.

Ein Ghazal
quelle
4
public static List<KeyValuePair<string, string>> GetProperties(object item) //where T : class
    {
        var result = new List<KeyValuePair<string, string>>();
        if (item != null)
        {
            var type = item.GetType();
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var pi in properties)
            {
                var selfValue = type.GetProperty(pi.Name).GetValue(item, null);
                if (selfValue != null)
                {
                    result.Add(new KeyValuePair<string, string>(pi.Name, selfValue.ToString()));
                }
                else
                {
                    result.Add(new KeyValuePair<string, string>(pi.Name, null));
                }
            }
        }
        return result;
    }

Auf diese Weise erhalten Sie alle Eigenschaften mit ihren Werten in einer Liste.

Boncho Valkov
quelle
Warum machen Sie das: type.GetProperty(pi.Name)wenn das == für die Variable ist pi?
Weston
Wenn Sie c # 6.0 verwenden, ifselfValue?.ToString()ifselfValue==null?null:selfValue.ToString()
entfernen Sie
Auch eine Liste von List<KeyValuePair<ist seltsam, verwenden Sie ein WörterbuchDictionary<string, string>
Weston
3

Der folgende Code ist eine rekursive Methode zum Anzeigen der gesamten Hierarchie aller in der Objektinstanz enthaltenen Eigenschaftsnamen und -werte. Diese Methode verwendet eine vereinfachte Version der GetPropertyValue()Antwort von AlexD oben in diesem Thread. Dank dieses Diskussionsthreads konnte ich herausfinden, wie das geht!

Mit dieser Methode zeige ich beispielsweise eine Explosion oder einen Speicherauszug aller Eigenschaften in einer WebServiceAntwort, indem ich die Methode wie folgt aufrufe:

PropertyValues_byRecursion("Response", response, false);

public static object GetPropertyValue(object srcObj, string propertyName)
{
  if (srcObj == null) 
  {
    return null; 
  }
  PropertyInfo pi = srcObj.GetType().GetProperty(propertyName.Replace("[]", ""));
  if (pi == null)
  {
    return null;
  }
  return pi.GetValue(srcObj);
}

public static void PropertyValues_byRecursion(string parentPath, object parentObj, bool showNullValues)
{
  /// Processes all of the objects contained in the parent object.
  ///   If an object has a Property Value, then the value is written to the Console
  ///   Else if the object is a container, then this method is called recursively
  ///       using the current path and current object as parameters

  // Note:  If you do not want to see null values, set showNullValues = false

  foreach (PropertyInfo pi in parentObj.GetType().GetTypeInfo().GetProperties())
  {
    // Build the current object property's namespace path.  
    // Recursion extends this to be the property's full namespace path.
    string currentPath = parentPath + "." + pi.Name;

    // Get the selected property's value as an object
    object myPropertyValue = GetPropertyValue(parentObj, pi.Name);
    if (myPropertyValue == null)
    {
      // Instance of Property does not exist
      if (showNullValues)
      {
        Console.WriteLine(currentPath + " = null");
        // Note: If you are replacing these Console.Write... methods callback methods,
        //       consider passing DBNull.Value instead of null in any method object parameters.
      }
    }
    else if (myPropertyValue.GetType().IsArray)
    {
      // myPropertyValue is an object instance of an Array of business objects.
      // Initialize an array index variable so we can show NamespacePath[idx] in the results.
      int idx = 0;
      foreach (object business in (Array)myPropertyValue)
      {
        if (business == null)
        {
          // Instance of Property does not exist
          // Not sure if this is possible in this context.
          if (showNullValues)
          {
            Console.WriteLine(currentPath  + "[" + idx.ToString() + "]" + " = null");
          }
        }
        else if (business.GetType().IsArray)
        {
          // myPropertyValue[idx] is another Array!
          // Let recursion process it.
          PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
        }
        else if (business.GetType().IsSealed)
        {
          // Display the Full Property Path and its Value
          Console.WriteLine(currentPath + "[" + idx.ToString() + "] = " + business.ToString());
        }
        else
        {
          // Unsealed Type Properties can contain child objects.
          // Recurse into my property value object to process its properties and child objects.
          PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
        }
        idx++;
      }
    }
    else if (myPropertyValue.GetType().IsSealed)
    {
      // myPropertyValue is a simple value
      Console.WriteLine(currentPath + " = " + myPropertyValue.ToString());
    }
    else
    {
      // Unsealed Type Properties can contain child objects.
      // Recurse into my property value object to process its properties and child objects.
      PropertyValues_byRecursion(currentPath, myPropertyValue, showNullValues);
    }
  }
}
Gridtrak
quelle
3
public static TValue GetFieldValue<TValue>(this object instance, string name)
{
    var type = instance.GetType(); 
    var field = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.FieldType) && e.Name == name);
    return (TValue)field?.GetValue(instance);
}

public static TValue GetPropertyValue<TValue>(this object instance, string name)
{
    var type = instance.GetType();
    var field = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.PropertyType) && e.Name == name);
    return (TValue)field?.GetValue(instance);
}
Rahma Samaroon
quelle
3
public class YourClass
{
    //Add below line in your class
    public object this[string propertyName] => GetType().GetProperty(propertyName)?.GetValue(this, null);
    public string SampleProperty { get; set; }
}

//And you can get value of any property like this.
var value = YourClass["SampleProperty"];
Komal Narang
quelle
3

Die folgende Methode funktioniert perfekt für mich:

class MyClass {
    public string prop1 { set; get; }

    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }
}

So erhalten Sie den Eigenschaftswert:

MyClass t1 = new MyClass();
...
string value = t1["prop1"].ToString();

So legen Sie den Eigenschaftswert fest:

t1["prop1"] = value;
Derrick.X
quelle
2
Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType)
Kyle
quelle
2

Hier ist eine andere Möglichkeit, eine verschachtelte Eigenschaft zu finden, für die die Zeichenfolge nicht erforderlich ist, um den Verschachtelungspfad anzugeben. Gutschrift an Ed S. für die Single-Property-Methode.

    public static T FindNestedPropertyValue<T, N>(N model, string propName) {
        T retVal = default(T);
        bool found = false;

        PropertyInfo[] properties = typeof(N).GetProperties();

        foreach (PropertyInfo property in properties) {
            var currentProperty = property.GetValue(model, null);

            if (!found) {
                try {
                    retVal = GetPropValue<T>(currentProperty, propName);
                    found = true;
                } catch { }
            }
        }

        if (!found) {
            throw new Exception("Unable to find property: " + propName);
        }

        return retVal;
    }

        public static T GetPropValue<T>(object srcObject, string propName) {
        return (T)srcObject.GetType().GetProperty(propName).GetValue(srcObject, null);
    }
Recursor
quelle
Es ist möglicherweise besser zu überprüfen, ob Type.GetPropertyzurückgegeben wird, null anstatt aufzurufen GetValueund NullReferenceExceptions in eine Schleife zu werfen.
Groo
2

Sie erwähnen nie, welches Objekt Sie untersuchen, und da Sie diejenigen ablehnen, die auf ein bestimmtes Objekt verweisen, gehe ich davon aus, dass Sie ein statisches Objekt meinen.

using System.Reflection;
public object GetPropValue(string prop)
{
    int splitPoint = prop.LastIndexOf('.');
    Type type = Assembly.GetEntryAssembly().GetType(prop.Substring(0, splitPoint));
    object obj = null;
    return type.GetProperty(prop.Substring(splitPoint + 1)).GetValue(obj, null);
}

Beachten Sie, dass ich das zu untersuchende Objekt mit der lokalen Variablen markiert habe obj. nullbedeutet statisch, andernfalls stellen Sie es auf das ein, was Sie wollen. Beachten Sie auch, dass dies GetEntryAssembly()eine der wenigen verfügbaren Methoden ist, um die "laufende" Assembly zu erhalten. Sie können damit herumspielen, wenn Sie Schwierigkeiten beim Laden des Typs haben.

Guvante
quelle
2

Schauen Sie sich die Heleonix.Reflection- Bibliothek an. Sie können Mitglieder über Pfade abrufen / setzen / aufrufen oder einen Getter / Setter (Lambda in einem Delegaten kompiliert) erstellen, der schneller als die Reflexion ist. Zum Beispiel:

var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);

Oder erstellen Sie einen Getter einmal und zwischenspeichern Sie ihn zur Wiederverwendung (dies ist leistungsfähiger, löst jedoch möglicherweise eine NullReferenceException aus, wenn ein Zwischenmitglied null ist):

var getter = Reflector.CreateGetter<DateTime, int>("Date.Year", typeof(DateTime));
getter(DateTime.Now);

Wenn Sie List<Action<object, object>>verschiedene Getter erstellen möchten , geben Sie einfach Basistypen für kompilierte Delegaten an (Typkonvertierungen werden zu kompilierten Lambdas hinzugefügt):

var getter = Reflector.CreateGetter<object, object>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
Hennadii Lutsyshyn
quelle
1
Verwenden Sie niemals Bibliotheken von Drittanbietern, wenn Sie diese in angemessener Zeit in 5-10 Zeilen in Ihrem eigenen Code implementieren können.
Artem G
1

kürzerer Weg ....

var a = new Test { Id = 1 , Name = "A" , date = DateTime.Now};
var b = new Test { Id = 1 , Name = "AXXX", date = DateTime.Now };

var compare = string.Join("",a.GetType().GetProperties().Select(x => x.GetValue(a)).ToArray())==
              string.Join("",b.GetType().GetProperties().Select(x => x.GetValue(b)).ToArray());
Budiantowang
quelle
1

jheddings und AlexD haben beide hervorragende Antworten zum Auflösen von Eigenschaftszeichenfolgen geschrieben. Ich würde meine gerne in die Mischung einfließen lassen, da ich genau zu diesem Zweck eine eigene Bibliothek geschrieben habe.

Die Hauptklasse von Pather.CSharp istResolver. Standardmäßig können Eigenschaften, Array- und Wörterbucheinträge aufgelöst werden.

Zum Beispiel, wenn Sie ein solches Objekt haben

var o = new { Property1 = new { Property2 = "value" } };

und wollen bekommen Property2, können Sie es so machen:

IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path); 
//=> "value"

Dies ist das grundlegendste Beispiel für die Pfade, die aufgelöst werden können. Wenn Sie sehen möchten, was es sonst noch kann oder wie Sie es erweitern können, gehen Sie einfach zu seiner Github-Seite .

Domysee
quelle
0

Hier ist meine Lösung. Es funktioniert auch mit COM-Objekten und ermöglicht den Zugriff auf Sammlungs- / Array-Elemente von COM-Objekten.

public static object GetPropValue(this object obj, string name)
{
    foreach (string part in name.Split('.'))
    {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        if (type.Name == "__ComObject")
        {
            if (part.Contains('['))
            {
                string partWithoundIndex = part;
                int index = ParseIndexFromPropertyName(ref partWithoundIndex);
                obj = Versioned.CallByName(obj, partWithoundIndex, CallType.Get, index);
            }
            else
            {
                obj = Versioned.CallByName(obj, part, CallType.Get);
            }
        }
        else
        {
            PropertyInfo info = type.GetProperty(part);
            if (info == null) { return null; }
            obj = info.GetValue(obj, null);
        }
    }
    return obj;
}

private static int ParseIndexFromPropertyName(ref string name)
{
    int index = -1;
    int s = name.IndexOf('[') + 1;
    int e = name.IndexOf(']');
    if (e < s)
    {
        throw new ArgumentException();
    }
    string tmp = name.Substring(s, e - s);
    index = Convert.ToInt32(tmp);
    name = name.Substring(0, s - 1);
    return index;
}
user3175253
quelle
0

Folgendes habe ich aufgrund anderer Antworten erhalten. Ein wenig übertrieben, wenn es darum geht, mit der Fehlerbehandlung so spezifisch zu werden.

public static T GetPropertyValue<T>(object sourceInstance, string targetPropertyName, bool throwExceptionIfNotExists = false)
{
    string errorMsg = null;

    try
    {
        if (sourceInstance == null || string.IsNullOrWhiteSpace(targetPropertyName))
        {
            errorMsg = $"Source object is null or property name is null or whitespace. '{targetPropertyName}'";
            Log.Warn(errorMsg);

            if (throwExceptionIfNotExists)
                throw new ArgumentException(errorMsg);
            else
                return default(T);
        }

        Type returnType = typeof(T);
        Type sourceType = sourceInstance.GetType();

        PropertyInfo propertyInfo = sourceType.GetProperty(targetPropertyName, returnType);
        if (propertyInfo == null)
        {
            errorMsg = $"Property name '{targetPropertyName}' of type '{returnType}' not found for source object of type '{sourceType}'";
            Log.Warn(errorMsg);

            if (throwExceptionIfNotExists)
                throw new ArgumentException(errorMsg);
            else
                return default(T);
        }

        return (T)propertyInfo.GetValue(sourceInstance, null);
    }
    catch(Exception ex)
    {
        errorMsg = $"Problem getting property name '{targetPropertyName}' from source instance.";
        Log.Error(errorMsg, ex);

        if (throwExceptionIfNotExists)
            throw;
    }

    return default(T);
}
Jeff Codes
quelle