Получить значение свойства из строки, используя reflection в C #

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

Функция GetSourceValue имеет переключатель, сравнивающий различные типы, но я хочу удалить эти типы и свойства и получить GetSourceValue значение свойства, используя только одну строку в качестве параметра. Я хочу передать class и свойство в строке и разрешить значение свойства.

Это возможно?

1 версия веб-архива оригинальной записи в блоге

21 Solutions collect form web for “Получить значение свойства из строки, используя reflection в C #”

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

Конечно, вы захотите добавить валидацию и еще много чего, но это и есть ее суть.

Как насчет чего-то вроде этого:

 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(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(now, "TimeOfDay.Minutes"); int hrs = now.GetPropValue("TimeOfDay.Hours"); 

Вы можете использовать эти методы как статические методы или расширения.

Добавить в любой 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"]; 

Как насчет использования CallByName пространства имен Microsoft.VisualBasic.dll ( Microsoft.VisualBasic.dll )? Он использует reflection для получения свойств, полей и методов обычных объектов, объектов COM и даже динамических объектов.

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

а потом

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

Отличный ответ от джеданий. Я хотел бы улучшить его, позволяя ссылаться на агрегированные массивы или коллекции объектов, так что 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 Array[]; 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; } 

Об обсуждении вложенных свойств вы можете избежать всех отражений, если вы используете DataBinder.Eval Method (Object, String) как показано ниже:

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

Конечно, вам нужно добавить ссылку на сборку System.Web , но это, вероятно, не имеет большого значения.

Если я использую код из Ed S., я получаю

‘ReflectionExtensions.GetProperty (Тип, строка)’ недоступен из-за его уровня защиты

Кажется, что GetProperty() недоступен в Xamarin.Forms. TargetFrameworkProfile – это Profile7 в моей переносимой библиотеке classов (.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)); if(property != null) { return property.GetValue(source); } return null; } 

Источник

Использование PropertyInfo пространства имен System.Reflection . Отражение компилируется просто отлично, независимо от того, какое свойство мы пытаемся получить. Ошибка будет появляться во время выполнения.

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

Он отлично работает, чтобы получить свойство Location объекта

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

Мы получим Местоположение: {X = 71, Y = 27} Мы также можем вернуть location.X или location.Y таким же образом.

 public static List> GetProperties(object item) //where T : class { var result = new List>(); 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(pi.Name, selfValue.ToString())); } else { result.Add(new KeyValuePair(pi.Name, null)); } } } return result; } 

Это способ получить все свойства со своими значениями в списке.

Метод вызова изменился в стандарте .NET (начиная с версии 1.6). Также мы можем использовать нулевой условный оператор C # 6.

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

Вот еще один способ найти nested свойство, которое не требует, чтобы строка указывала вам путь вложенности. Приобретите Ed S. для метода одиночных свойств.

  public static T FindNestedPropertyValue(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(currentProperty, propName); found = true; } catch { } } } if (!found) { throw new Exception("Unable to find property: " + propName); } return retVal; } public static T GetPropValue(object srcObject, string propName) { return (T)srcObject.GetType().GetProperty(propName).GetValue(srcObject, null); } 

Вы никогда не упоминаете, какой объект вы проверяете, и поскольку вы отвергаете те, которые ссылаются на данный объект, я предполагаю, что вы имеете в виду статичный.

 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() является одним из нескольких доступных способов получения «бегущей» сборки, вы можете захотеть поиграть с ней, если вам тяжело загружать этот тип.

Следующий код – это рекурсивный метод для отображения всей иерархии всех Имен. Имен и Значений, содержащихся в экземпляре объекта. Этот метод использует упрощенную версию ответа GetPropertyValue() AlexD выше в этом streamе. Благодаря этой дискуссионной теме я смог выяснить, как это сделать!

Например, я использую этот метод, чтобы показать взрыв или дамп всех свойств в ответе 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); } } } 
 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"]; 
 Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType) 

более короткий путь ….

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

jheddings и AlexD оба отлично отзывались о том, как разрешать строки свойств. Я хотел бы бросить шахту в микс, так как я написал специальную библиотеку именно для этой цели.

Основной class 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 .

 public static TValue GetFieldValue(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(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); } 

Вот мое решение. Он также работает с объектами 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; } 

Метод ниже подходит для меня идеально:

 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; 

Посмотрите библиотеку Heleonix.Reflection . Вы можете получить / установить / вызывать членов по путям или создать геттер / сеттер (lambda, скомпилированный в делегат), который быстрее, чем reflection. Например:

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

Или создайте геттер один раз и кеш для повторного использования (это более результативно, но может вызывать исключение NullReferenceException, если промежуточный член равен нулю):

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

Или, если вы хотите создать List> разных геттеров, просто укажите базовые типы для скомпилированных делегатов (типы конверсий будут добавлены в скомпилированные lambdas):

 var getter = Reflector.CreateGetter("Date.Year", typeof(DateTime)); getter(DateTime.Now); 
  • C # Использование Reflection для копирования свойств базового classа
  • Как получить имя и тип вызывающего метода с помощью отражения?
  • Получить тип общего параметра в Java с reflectionм
  • Что может вызвать java.lang.reflect.InvocationTargetException?
  • Как перечислить все функции в модуле Python?
  • Как использовать reflection для вызова частного метода?
  • Можете ли вы использовать reflection, чтобы найти имя текущего исполняемого метода?
  • Любой способ вызвать частный метод?
  • Получить общий тип classа во время выполнения
  • Как я могу оценивать выражение C # динамически?
  • Type.GetType ("namespace.abClassName") возвращает null
  • Interesting Posts

    Не удается ssh для моего iphone: ssh_exchange_identification: соединение закрыто удаленным хостом

    Сколько памяти будет освобождено, если указатель изменится на C?

    Текст маркировки на Android

    Как заставить Apache следовать символическим ссылкам?

    Как установить 7zip, чтобы я мог запускать его из терминала в OS X

    Ярлык клавиатуры для увеличения текущего окна / приложения в OSX

    Каково использование / значение символа @ в именах переменных на C #?

    Что мне нужно знать, прежде чем обновлять процессор ноутбука?

    Маркировка / маркировка оконных файлов

    Как я могу сделать ссылку на клики в NSAttributedString?

    Inno Setup: как автоматически удалить предыдущую установленную версию?

    Код C ++ для проверки гипотезы Collatz быстрее, чем assembly вручную – почему?

    Селекторы jQuery с переменными

    Каков наилучший подход для использования Enum в качестве одноэлементной на Java?

    Windows 7 имеет странную идею о том, что в полноэкранном режиме

    Давайте будем гением компьютера.