รับค่าคุณสมบัติจากสตริงโดยใช้การสะท้อนใน C #


928

ฉันพยายามใช้การแปลงข้อมูลโดยใช้ตัวอย่างReflection 1ในรหัสของฉัน

GetSourceValueฟังก์ชั่นที่มีสวิทช์เปรียบเทียบหลากหลายชนิด แต่ฉันต้องการที่จะลบประเภทนี้และคุณสมบัติและมีการGetSourceValueรับค่าของทรัพย์สินที่ใช้เพียงสายเดียวที่เป็นพารามิเตอร์ ฉันต้องการส่งคลาสและคุณสมบัติในสตริงและแก้ไขค่าของคุณสมบัติ

เป็นไปได้ไหม

1 Web Archive โพสต์บล็อกดั้งเดิม

คำตอบ:


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

แน่นอนคุณจะต้องเพิ่มการตรวจสอบและ whatnot แต่นั่นคือส่วนสำคัญของมัน


8
ดีและเรียบง่าย! ฉันต้องการทำให้เป็นเรื่องทั่วไป:public static T GetPropertyValue<T>(object obj, string propName) { return (T)obj.GetType().GetProperty(propName).GetValue(obj, null); }
Ohad Schneider

2
การเพิ่มประสิทธิภาพสามารถลบความเสี่ยงของข้อยกเว้นโมฆะเช่นนี้: " src.GetType().GetProperty(propName)?.GetValue(src, null);";)
shA.t

8
@ shA.t: ฉันคิดว่านั่นเป็นความคิดที่ไม่ดี คุณจะแยกความแตกต่างระหว่างค่า Null ของคุณสมบัติที่มีอยู่หรือไม่มีคุณสมบัติได้อย่างไร ฉันค่อนข้างจะรู้ทันทีว่าฉันส่งชื่ออสังหาริมทรัพย์ที่ไม่ดี นี่ไม่ใช่รหัสการผลิต แต่การปรับปรุงที่ดีกว่าคือการโยนข้อยกเว้นที่เฉพาะเจาะจงมากขึ้น (เช่นตรวจสอบการเปิดGetPropertyและการโยนPropertyNotFoundExceptionหรือสิ่งใด ๆ ที่เป็นโมฆะ)
35499 Ed Ed

210

เกี่ยวกับบางสิ่งเช่นนี้:

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

สิ่งนี้จะช่วยให้คุณสามารถสืบทอดคุณสมบัติโดยใช้สตริงเดียวเช่นนี้

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

คุณสามารถใช้วิธีการเหล่านี้เป็นวิธีการคงที่หรือส่วนขยาย


3
@ FredJand ดีใจที่คุณสะดุดมัน! มันน่าประหลาดใจเสมอเมื่อโพสต์เก่าเหล่านี้เปิดขึ้น มันค่อนข้างคลุมเครือเล็กน้อยดังนั้นฉันจึงเพิ่มข้อความเล็กน้อยเพื่ออธิบาย ฉันได้เปลี่ยนไปใช้วิธีการเหล่านี้เป็นส่วนขยายและเพิ่มรูปแบบ generics ดังนั้นฉันจึงเพิ่มที่นี่
jheddings

ทำไมตัวป้องกัน null ใน foreach และไม่อยู่ด้านบน
Santhos

4
@Santos เนื่องจาก 'obj' ถูกนิยามใหม่ในเนื้อความของ foreach loop จะถูกตรวจสอบในระหว่างการทำซ้ำแต่ละครั้ง
jheddings

มีประโยชน์ แต่ในกรณีขอบที่หนึ่งในคุณสมบัติซ้อนกันอาจถูกซ่อนไว้ (โดยใช้ตัวดัดแปลง 'ใหม่') มันจะส่งข้อยกเว้นสำหรับการค้นหาคุณสมบัติที่ซ้ำกัน มันจะเป็น neater เพื่อติดตามชนิดของคุณสมบัติล่าสุดและใช้PropertyInfo.PropertyTypeแทนobj.GetType()คุณสมบัติซ้อนกันเช่นเดียวกับการเข้าถึงคุณสมบัติบนคุณสมบัติที่ซ้อนกัน
Nullius

คุณสามารถใช้nameofนิพจน์ตั้งแต่ C # 6 ดังนี้: nameof(TimeOfDay.Minutes)บนพารามิเตอร์ name เมื่อเรียกใช้ฟังก์ชันเพื่อกำจัดสายเวทย์มนตร์และเพิ่มความปลอดภัยเวลาคอมไพล์ให้กับการเรียกเหล่านี้
เรียบ

74

เพิ่มไปที่ใด ๆ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; }
}

จากนั้นคุณสามารถใช้เป็น:

Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];

@EduardoCuomo: เป็นไปได้ไหมที่จะใช้การไตร่ตรองกับสิ่งนี้ดังนั้นคุณไม่จำเป็นต้องรู้ว่าสมาชิกของคลาสมีอะไรบ้าง?
คนของเราใน Bananas

เป็นไปได้ไหมถ้า "บาร์" เป็นวัตถุ?
big_water

@big_water SetValueและวิธีการทำงานร่วมกับGetValue Objectหากคุณต้องการทำงานกับประเภทเฉพาะคุณควรส่งผลลัพธ์GetValueและใช้เพื่อกำหนดค่าด้วยSetValue
Eduardo Cuomo

ขออภัย @ OurManinBananas ฉันไม่เข้าใจคำถามของคุณ เธออยากทำอะไรล่ะ?
Eduardo Cuomo

วิธีการประเภทนี้ชื่ออะไร?
Sahan Chinthaka

45

สิ่งที่เกี่ยวกับการใช้CallByNameของMicrosoft.VisualBasicnamespace ( Microsoft.VisualBasic.dll)? มันใช้การสะท้อนเพื่อรับคุณสมบัติเขตข้อมูลและวิธีการของวัตถุปกติวัตถุ COM และแม้แต่วัตถุแบบไดนามิก

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

แล้ว

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();

5
คำแนะนำที่น่าสนใจการตรวจสอบเพิ่มเติมพิสูจน์ว่าสามารถจัดการได้ทั้งฟิลด์และคุณสมบัติวัตถุ COM และสามารถจัดการการเชื่อมโยงแบบไดนามิกได้อย่างถูกต้อง !
IllidanS4 ต้องการโมนิก้ากลับ

ฉันได้รับข้อผิดพลาด: สมาชิกสาธารณะ 'MyPropertyName' บนประเภท 'MyType' ไม่พบ
vldmrrdjcc

30

คำตอบที่ดีโดย jheddings ฉันต้องการที่จะปรับปรุงให้สามารถอ้างอิงอาเรย์รวมหรือคอลเลกชันของวัตถุเพื่อให้ propertyName สามารถเป็น property1.property2 [X] .property3:

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

สิ่งที่เกี่ยวกับรายการของรายการเข้าถึงโดย MasterList [0] [1]
Jesse Adam

เป็น Array -> เป็นวัตถุ [] ส่งผลให้เกิดข้อยกเว้น Nullreference อะไรที่เหมาะกับฉัน (prop ไม่ใช่วิธีที่มีประสิทธิภาพมากที่สุด) คือการส่ง unknownCollection ไปที่ IEnumerable และมากกว่าใช้ ToArray () กับผลลัพธ์ ซอ
Jeroen Jonkman

14

ถ้าฉันใช้รหัสจากEd S.ฉันจะได้รับ

'ReflectionExtensions.GetProperty (ประเภท, สตริง)' ไม่สามารถเข้าถึงได้เนื่องจากระดับการป้องกัน

ดูเหมือนว่าGetProperty()ไม่สามารถใช้ได้ใน Xamarin.Forms TargetFrameworkProfileอยู่Profile7ใน Portable Class Library ของฉัน (.NET Framework 4.5, Windows 8, ASP.NET Core 1.0, Xamarin.Android, Xamarin.iOS, Xamarin.iOS Classic)

ตอนนี้ฉันพบวิธีแก้ปัญหาการทำงาน:

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

แหล่ง


4
การปรับปรุงเพียงเล็กน้อยที่เป็นไปได้ แทนที่ถ้า IF และส่งคืนโดย: return property? .GetValue (แหล่งที่มา);
Tomino

11

เกี่ยวกับการสนทนาคุณสมบัติที่ซ้อนกันคุณสามารถหลีกเลี่ยงสิ่งสะท้อนทั้งหมดถ้าคุณใช้DataBinder.Eval Method (Object, String)ดังต่อไปนี้:

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

แน่นอนคุณจะต้องเพิ่มการอ้างอิงไปยังSystem.Webแอสเซมบลี แต่นี่อาจไม่ใช่เรื่องใหญ่


8

วิธีการโทรมีการเปลี่ยนแปลงใน. NET Standard (จนถึง 1.6) นอกจากนี้เราสามารถใช้โอเปอเรเตอร์ที่มีเงื่อนไขของ C # 6

using System.Reflection; 
public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}

1
ขึ้นสำหรับการใช้? operator
blfuentes

4

การใช้ PropertyInfo ของSystem.Reflection namespace การรวบรวมภาพสะท้อนนั้นทำได้ดีไม่ว่าเราจะพยายามเข้าถึงทรัพย์สินใด ข้อผิดพลาดจะเกิดขึ้นในช่วงเวลาทำงาน

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

ใช้งานได้ดีเพื่อรับคุณสมบัติตำแหน่งของวัตถุ

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

เราจะได้ตำแหน่ง: {X = 71, Y = 27} นอกจากนี้เรายังสามารถส่งคืนตำแหน่ง X หรือตำแหน่ง Y ในลักษณะเดียวกัน


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

นี่คือวิธีรับคุณสมบัติทั้งหมดพร้อมค่าในรายการ


ทำไมจะทำเช่นนี้: type.GetProperty(pi.Name)เมื่อที่เป็น == ตัวแปรpi?
weston

หากคุณใช้ c # 6.0 ให้กำจัดifและทำselfValue?.ToString()มิฉะนั้นให้กำจัดifและใช้งานselfValue==null?null:selfValue.ToString()
weston

นอกจากนี้ยังมีรายการList<KeyValuePair<แปลก ๆ ให้ใช้พจนานุกรมDictionary<string, string>
weston

3

รหัสต่อไปนี้เป็นวิธีการเรียกซ้ำสำหรับการแสดงลำดับชั้นทั้งหมดของชื่อคุณสมบัติและค่าทั้งหมดที่มีอยู่ในอินสแตนซ์ของวัตถุ วิธีนี้ใช้GetPropertyValue()คำตอบของ AlexD ในเวอร์ชันที่เรียบง่ายด้านบนในชุดข้อความนี้ ขอบคุณกระทู้สนทนานี้ฉันสามารถหาวิธีการทำสิ่งนี้!

ตัวอย่างเช่นฉันใช้วิธีนี้เพื่อแสดงการระเบิดหรือการถ่ายโอนข้อมูลของคุณสมบัติทั้งหมดในการWebServiceตอบสนองโดยการเรียกวิธีดังต่อไปนี้:

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

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

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"];

3

วิธีการด้านล่างใช้งานได้สมบูรณ์แบบสำหรับฉัน:

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

วิธีรับค่าคุณสมบัติ:

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

วิธีตั้งค่าคุณสมบัติ:

t1["prop1"] = value;


2

นี่เป็นอีกวิธีหนึ่งในการค้นหาคุณสมบัติแบบซ้อนที่ไม่ต้องการสตริงเพื่อบอกเส้นทางการซ้อน ให้เครดิตกับ Ed S. สำหรับวิธีการของคุณสมบัติเดี่ยว

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

มันอาจจะดีกว่าที่จะตรวจสอบว่าType.GetPropertyผลตอบแทนnull แทนการโทรGetValueและมีการNullReferenceExceptionโยนในวง
Groo

2

คุณไม่เคยพูดถึงสิ่งที่คุณกำลังตรวจสอบวัตถุและเนื่องจากคุณปฏิเสธวัตถุที่อ้างอิงวัตถุที่กำหนดฉันจะถือว่าคุณหมายถึงวัตถุคงที่

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

objหมายเหตุที่ผมทำเครื่องหมายวัตถุที่จะถูกตรวจสอบกับตัวแปรท้องถิ่น nullหมายถึงคงที่มิฉะนั้นกำหนดเป็นสิ่งที่คุณต้องการ นอกจากนี้โปรดทราบว่าวิธีGetEntryAssembly()นี้เป็นวิธีการหนึ่งในไม่กี่วิธีในการรับชุดประกอบ "ที่กำลังทำงานอยู่" คุณอาจต้องการเล่นกับมันหากคุณประสบปัญหาในการโหลดประเภท


2

ลองดูที่Heleonix.Reflection library คุณสามารถรับ / set / เรียกใช้สมาชิกตามเส้นทางหรือสร้าง getter / setter (แลมบ์ดาที่รวบรวมเป็นตัวแทน) ซึ่งเร็วกว่าการสะท้อนกลับ ตัวอย่างเช่น:

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

หรือสร้างผู้ทะเยอทะยานหนึ่งครั้งและแคชเพื่อนำมาใช้ใหม่ (นี่คือประสิทธิภาพมากกว่า แต่อาจโยน NullReferenceException หากสมาชิกระดับกลางเป็นโมฆะ):

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

หรือถ้าคุณต้องการสร้างผู้ได้รับที่List<Action<object, object>>ต่างกันเพียงแค่ระบุประเภทฐานสำหรับผู้ได้รับการรวบรวม (การแปลงประเภทจะถูกเพิ่มลงใน lambdas ที่คอมไพล์แล้ว):

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

1
อย่าใช้ libs ของบุคคลที่สามหากคุณสามารถนำไปใช้ในรหัสของคุณเองในเวลาที่เหมาะสมใน 5-10 บรรทัด
Artem G

1

วิธีที่สั้นกว่า ....

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

1

jheddingsและAlexDทั้งคู่เขียนคำตอบที่ยอดเยี่ยมเกี่ยวกับวิธีการแก้ไขสตริงคุณสมบัติ ฉันต้องการที่จะโยนระเบิดในการผสมผสานตั้งแต่ฉันเขียนห้องสมุดเฉพาะสำหรับวัตถุประสงค์นั้น

Pather.CSharpResolverระดับหลักก็คือ โดยค่าเริ่มต้นสามารถแก้ไขรายการคุณสมบัติอาร์เรย์และพจนานุกรม

ตัวอย่างเช่นถ้าคุณมีวัตถุแบบนี้

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

และต้องการได้รับProperty2คุณสามารถทำสิ่งนี้ได้:

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

นี่เป็นตัวอย่างพื้นฐานที่สุดของเส้นทางที่สามารถแก้ไขได้ หากคุณต้องการที่จะเห็นอะไรที่มันสามารถหรือวิธีการที่คุณสามารถขยายมันเพียงแค่หัวของหน้า Github


0

นี่คือทางออกของฉัน มันยังทำงานกับวัตถุ COM และอนุญาตให้เข้าถึงรายการคอลเลกชัน / อาร์เรย์จากวัตถุ COM

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

0

นี่คือสิ่งที่ฉันได้จากคำตอบอื่น ๆ overkill เล็กน้อยในการรับเฉพาะกับการจัดการข้อผิดพลาด

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);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.