다음 코드를 고려하십시오개체가 복사되는 이유는 무엇입니까?
class ObjectAccessor {
...
static public void SetValueAtPath(ref object obj, List<PathEntry> path,
object value)
{
if (path.Count == 0)
obj = value;
object container = obj;
for (int i = 0; i < path.Count - 1; i++)
container = GetMember(container, path[i]);
SetMember(container, path[path.Count - 1], value);
}
...
}
나는 path
에 따라 발견되는 특정 필드 또는 obj
내부 깊은 속성에 value
을 할당하려는 SetValueAtPath
를 호출. container
변수는 필드가 들어있는 실제 객체를 가리키고 해당 필드를 수정하려면 SetMember
이 필요합니다. 컨테이너가 참조이므로 원본 obj
도 수정해야합니다. 그러나 디버거에 따르면 container
만 수정되고 obj
은 변경되지 않습니다. 사본이 어디서 왜 만들어 졌습니까? 여기
class PathEntry
{
public enum PathEntryKind
{
Index,
Name
}
public PathEntryKind Kind;
public int Index; // Kind == Index
public string Name; // Kind == Name
}
class ObjectAccessor {
...
static public object GetMember(object obj, PathEntry member)
{
if (member.Kind == PathEntry.PathEntryKind.Index)
return ((IList)obj)[member.Index];
else
return GetFieldOrPropertyValue(obj, member.Name);
}
static public object GetFieldOrPropertyValue(object obj, string name)
{
FieldInfo fieldInfo = obj.GetType().GetField(name, BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
PropertyInfo propertyInfo = obj.GetType().GetProperty(name, BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
if (fieldInfo != null)
return fieldInfo.GetValue(obj);
else if (propertyInfo != null)
return propertyInfo.GetValue(obj, null);
throw new IncompatibleNativeTypeException();
}
static public void SetMember(object obj, PathEntry member, object value)
{
if (member.Kind == PathEntry.PathEntryKind.Index)
((IList)obj)[member.Index] = value;
else
SetFieldOrPropertyValue(obj, member.Name, value);
}
static public void SetFieldOrPropertyValue(object obj, string name, object value)
{
FieldInfo fieldInfo = obj.GetType().GetField(name, BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
PropertyInfo propertyInfo = obj.GetType().GetProperty(name, BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
if (fieldInfo != null)
fieldInfo.SetValue(obj, value);
else if (propertyInfo != null)
propertyInfo.SetValue(obj, value, null);
}
...
}
UPDATE :
object obj = ObjectConstructor.ConstructObject(encoding, objectType);
...
ObjectAccessor.SetValueAtPath(ref obj, encodingEntry.ValuePath, value);
@Kirk : 전화 사이트에서 코드 container
변수를 유혹 SetMember
을 실행 한 후 디버거에서 수정 된 문자열 필드가 null
에서 "Sergiy"
으로 변경되는 것을 볼 수 있으며, obj
과 동일한 필드로 이동하면 null
으로 남습니다.
, BTW 코드는 여기에 있습니다 : https://github.com/rryk/opensim-omp/blob/kiara/KIARA/ UPDATE
: https://github.com/rryk/opensim-omp/blob/kiara/KIARA.Test/FunctionMapingConfigTest.cs이
가 UPDATE : 크리스에 덕분에, 내가 깨달은 나는 다음 테스트에서 실행이 이상한 행동을 경험 문제점은 무엇이며 다음과 같이 코드를 다시 구현했습니다.
// Supports empty path in which case modifies passed obj as it's passed by reference.
static public void SetValueAtPath(ref object obj, List<PathEntry> path, object value)
{
if (path.Count == 0)
{
obj = value;
return;
}
// List of value types (structs) to be reassigned.
List<KeyValuePair<object, PathEntry>> valueTypeContainers = new List<KeyValuePair<object,PathEntry>>();
object container = obj;
for (int i = 0; i < path.Count - 1; i++)
{
object newContainer = GetMember(container, path[i]);
// Keep the trail of the value types (struct) or clear it if next container is non-value type.
if (newContainer.GetType().IsValueType)
valueTypeContainers.Add(new KeyValuePair<object, PathEntry>(container, path[i]));
else
valueTypeContainers.Clear();
container = newContainer;
}
SetMember(container, path[path.Count - 1], value);
// Reassign the value types (structs).
for (int i = valueTypeContainers.Count - 1; i >= 0; i--)
{
object valueContainer = valueTypeContainers[i].Key;
PathEntry pathEntry = valueTypeContainers[i].Value;
SetMember(valueContainer, pathEntry, container);
container = valueContainer;
}
}
'SetValueAtPath' (및 주변 코드)를 어떻게 호출하는지 표시 할 수 있습니까? –
Simon의 요청 외에도 "디버거에 따르면 컨테이너 만 수정되고 obj는 변경되지 않습니다."라는 의미를 자세히 설명하십시오. 어떤 의미에서 컨테이너가 수정 되었습니까? –
사이드 노트 : 나는 정상적인 생각 과정으로 이것을 재현 할 수 없다. 그래서 이상한 일이 벌어지고 있습니다 (나는 당신의 전화 사이트를 의심합니다.). –