C # Использование Reflection для копирования свойств базового classа

Я хотел бы обновить все свойства MyObject до другого с помощью Reflection. Проблема, в которую я вхожу, заключается в том, что конкретный объект наследуется от базового classа, а значения базового classа не обновляются.

Приведенный ниже код копирует значения свойств верхнего уровня.

public void Update(MyObject o) { MyObject copyObject = ... FieldInfo[] myObjectFields = o.GetType().GetFields( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo fi in myObjectFields) { fi.SetValue(copyObject, fi.GetValue(o)); } } 

Я искал, есть ли какие-либо атрибуты BindingFlags, которые я мог бы использовать, но безрезультатно.

5 Solutions collect form web for “C # Использование Reflection для копирования свойств базового classа”

Попробуй это:

 public void Update(MyObject o) { MyObject copyObject = ... Type type = o.GetType(); while (type != null) { UpdateForType(type, o, copyObject); type = type.BaseType; } } private static void UpdateForType(Type type, MyObject source, MyObject destination) { FieldInfo[] myObjectFields = type.GetFields( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo fi in myObjectFields) { fi.SetValue(destination, fi.GetValue(source)); } } 

Я написал это как метод расширения, который также работает с разными типами. Моя проблема заключалась в том, что у меня есть некоторые модели, связанные с формами asp mvc и другими объектами, сопоставленными с базой данных. В идеале у меня будет только 1 class, но сущность будет построена поэтапно, а модели asp mvc хотят сразу проверить всю модель.

Вот код:

 public static class ObjectExt { public static T1 CopyFrom(this T1 obj, T2 otherObject) where T1: class where T2: class { PropertyInfo[] srcFields = otherObject.GetType().GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty); PropertyInfo[] destFields = obj.GetType().GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty); foreach (var property in srcFields) { var dest = destFields.FirstOrDefault(x => x.Name == property.Name); if (dest != null && dest.CanWrite) dest.SetValue(obj, property.GetValue(otherObject, null), null); } return obj; } } 

Хм. Я думал, что GetFields получает от вас членов со всей цепи, и вам нужно явно BindingFlags.DeclaredOnly если вы не хотите унаследованных членов. Поэтому я сделал быстрый тест, и я был прав.

Затем я заметил что-то:

Я хотел бы обновить все свойства MyObject до другого с помощью Reflection. Проблема, в которую я вхожу, заключается в том, что конкретный объект наследуется от базового classа, а значения базового classа не обновляются.

Приведенный ниже код копирует значения свойств верхнего уровня.

 public void Update(MyObject o) { MyObject copyObject = ... FieldInfo[] myObjectFields = o.GetType().GetFields( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); 

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

 class L0 { public int f0; private int _p0; public int p0 { get { return _p0; } set { _p0 = value; } } } class L1 : L0 { public int f1; private int _p1; public int p1 { get { return _p1; } set { _p1 = value; } } } class L2 : L1 { public int f2; private int _p2; public int p2 { get { return _p2; } set { _p2 = value; } } } 

то a .GetFields на L2 с BindingFlags вами BindingFlags получат f0 , f1 , f2 и _p2 , но NOT p0 или p1 (которые являются свойствами, а не полями) OR _p0 или _p1 (которые являются частными для базовых classов и, следовательно, объекты типа L2 не имеют этих полей.

Если вы хотите скопировать свойства, попробуйте сделать то, что вы делаете, но вместо этого используйте .GetProperties .

Это не учитывает свойства с параметрами и не рассматривает ли частные получающие / устанавливающие аксессуры, которые могут быть недоступны, и не учитывает списки только для чтения, так что это расширенное решение?

Я попробовал конвертировать в C #, но обычные источники для этого не сделали этого, и у меня нет времени для его преобразования.

 '''  ''' Import the properties that match by name in the source to the target. ''' Object to import the properties into. ''' Object to import the properties from. '''  ''' True, if the import can without exception; otherwise, False.  Public Function Import(target As Object, source As Object) As Boolean Dim targetProperties As IEnumerable(Of Tuple(Of Reflection.PropertyInfo, Reflection.MethodInfo)) = (From aPropertyInfo In source.GetType().GetProperties(Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance) Let propertyAccessors = aPropertyInfo.GetAccessors(True) Let propertyMethods = aPropertyInfo.PropertyType.GetMethods() Let addMethod = (From aMethodInfo In propertyMethods Where aMethodInfo.Name = "Add" AndAlso aMethodInfo.GetParameters().Length = 1 Select aMethodInfo).FirstOrDefault() Where aPropertyInfo.CanRead AndAlso aPropertyInfo.GetIndexParameters().Length = 0 _ AndAlso (aPropertyInfo.CanWrite OrElse addMethod IsNot Nothing) _ AndAlso (From aMethodInfo In propertyAccessors Where aMethodInfo.IsPrivate _ OrElse (aMethodInfo.Name.StartsWith("get_") OrElse aMethodInfo.Name.StartsWith("set_"))).FirstOrDefault() IsNot Nothing Select New Tuple(Of Reflection.PropertyInfo, Reflection.MethodInfo)(aPropertyInfo, addMethod)) ' No properties to import into. If targetProperties.Count() = 0 Then Return True Dim sourceProperties As IEnumerable(Of Tuple(Of Reflection.PropertyInfo, Reflection.MethodInfo)) = (From aPropertyInfo In source.GetType().GetProperties(Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance) Let propertyAccessors = aPropertyInfo.GetAccessors(True) Let propertyMethods = aPropertyInfo.PropertyType.GetMethods() Let addMethod = (From aMethodInfo In propertyMethods Where aMethodInfo.Name = "Add" AndAlso aMethodInfo.GetParameters().Length = 1 Select aMethodInfo).FirstOrDefault() Where aPropertyInfo.CanRead AndAlso aPropertyInfo.GetIndexParameters().Length = 0 _ AndAlso (aPropertyInfo.CanWrite OrElse addMethod IsNot Nothing) _ AndAlso (From aMethodInfo In propertyAccessors Where aMethodInfo.IsPrivate _ OrElse (aMethodInfo.Name.StartsWith("get_") OrElse aMethodInfo.Name.StartsWith("set_"))).FirstOrDefault() IsNot Nothing Select New Tuple(Of Reflection.PropertyInfo, Reflection.MethodInfo)(aPropertyInfo, addMethod)) ' No properties to import. If sourceProperties.Count() = 0 Then Return True Try Dim currentPropertyInfo As Tuple(Of Reflection.PropertyInfo, Reflection.MethodInfo) Dim matchingPropertyInfo As Tuple(Of Reflection.PropertyInfo, Reflection.MethodInfo) ' Copy the properties from the source to the target, that match by name. For Each currentPropertyInfo In sourceProperties matchingPropertyInfo = (From aPropertyInfo In targetProperties Where aPropertyInfo.Item1.Name = currentPropertyInfo.Item1.Name).FirstOrDefault() ' If a property matches in the target, then copy the value from the source to the target. If matchingPropertyInfo IsNot Nothing Then If matchingPropertyInfo.Item1.CanWrite Then matchingPropertyInfo.Item1.SetValue(target, matchingPropertyInfo.Item1.GetValue(source, Nothing), Nothing) ElseIf matchingPropertyInfo.Item2 IsNot Nothing Then Dim isEnumerable As IEnumerable = TryCast(currentPropertyInfo.Item1.GetValue(source, Nothing), IEnumerable) If isEnumerable Is Nothing Then Continue For ' Invoke the Add method for each object in this property collection. For Each currentObject As Object In isEnumerable matchingPropertyInfo.Item2.Invoke(matchingPropertyInfo.Item1.GetValue(target, Nothing), New Object() {currentObject}) Next End If End If Next Catch ex As Exception Return False End Try Return True End Function 

Решение Bogdan Litescu отлично работает, хотя я бы также проверил, можете ли вы писать в собственность.

 foreach (var property in srcFields) { var dest = destFields.FirstOrDefault(x => x.Name == property.Name); if (dest != null) if (dest.CanWrite) dest.SetValue(obj, property.GetValue(otherObject, null), null); } 
Interesting Posts

Почему в classах C # 4.0 нет общей дисперсии?

Как создать базу данных в android?

Каков наилучший инструмент для измельчения файлов на карте памяти?

Как фильтровать определенные приложения для намерения ACTION_SEND (и устанавливать другой текст для каждого приложения)

Эквивалент chmod для изменения прав доступа к файлам в Windows

Учитывая массив чисел, возвращаем массив продуктов всех других чисел (без деления)

Как запустить приложение WinForm сведено к минимуму?

Запустить любой скрипт оболочки из Fish и импортировать все экспортированные переменные env?

Строки Java: compareTo () vs. equals ()

В чем разница между NULL, ‘\ 0’ и 0

Центрировать содержимое внутри столбца в Bootstrap 4

Как создать таблицу с помощью ASCII в консоли?

Планировщик задач Windows 7 не перечисляет мои пользовательские задачи.

Почему я не могу использовать метод overulateViewHolder override?

Почему основной метод Java статический?

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