(0, _b.a)()
гарантирует, что функция _b.a
вызывается с this
, установленным для глобального объекта (или если строгий режим включен, undefined
). Если вы должны были называть _b.a()
напрямую, то _b.a
вызывается с this
, установленным на _b
.
(0, _b.a)();
эквивалентно
0; // Ignore result
var tmp = _b.a;
tmp();
( ,
является оператором запятой, см. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator ).
Попробуйте это:
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 класс, но сущность строится поэтапно, и модели asp mvc хотят проверить всю модель сразу.
Вот код:
public static class ObjectExt
{
public static T1 CopyFrom<T1, T2>(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;
}
}
Это не учитывает свойства с параметрами и не учитывает частные методы доступа get / set, которые могут быть недоступны, а также не учитывает перечислимые элементы только для чтения, так что вот расширенное решение?
Я пытался конвертировать в C #, но обычные источники для этого не смогли этого сделать, и у меня нет времени конвертировать его самому.
''' <summary>
''' Import the properties that match by name in the source to the target.</summary>
''' <param name="target">Object to import the properties into.</param>
''' <param name="source">Object to import the properties from.</param>
''' <returns>
''' True, if the import can without exception; otherwise, False.</returns>
<System.Runtime.CompilerServices.Extension()>
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
Решение Богдана Литеску прекрасно работает, хотя я бы также проверил, можете ли вы написать в собственность.
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);
}
Хм. Я думал, что GetFields
дает вам участников на всем пути вверх по цепочке, и вам нужно было явно указать BindingFlags.DeclaredOnly
, если вы не хотели унаследованные члены. Я провел быстрый тест и оказался прав.
Затем я заметил кое-что:
Я хотел бы обновить все свойства от MyObject к другому, используя Отражение. Проблема, я иду в том, что конкретный объект унаследованный от базового класса и те значения базового класса свойства не обновлено.
Приведенный ниже код копируется поверх верхнего уровня. значения свойств.
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; }
}
}
, тогда .GetFields
на L2
с указанными вами BindingFlags
получит ] f0
, f1
, f2
и _p2
, но НЕ p0
или p1
(который являются свойствами, а не полями) OR _p0
или _p1
(которые являются частными для базовых классов и, следовательно, объекты типа L2
не имеют тех полей.
Если вы хотите скопировать свойства, попробуйте сделать то, что делаете, но вместо этого используйте .GetProperties
.