Здравствуйте, <Аноним>, Вы писали:
А>как передавать в функцию копию объекта класса, а не ссылку на него.
А>
А> public void MyFunc(MyClass F)
А> {
А> ArrayList Array = new ArrayList();
А> Array.Add(F);
А> Array.Add(F);
А> }
А>
А>при изменении второго элемента Array[1] меняется значение Array[0]. А>как этого избежать?
Вамм нужно клонировать F (если это не структура). Общего решения не существует. Частное -- склонировать приемлемым образом F и положить в массив вместо оригинального F.
Здравствуйте, Аноним, Вы писали:
А>как передавать в функцию копию объекта класса, а не ссылку на него.
А что значит "копию"? Копии бывают разные.
Если класс содержит поля, которые ссылаются на экземпляры других классов, нужно ли чтобы в копии объекта поля ссылались на копии других классов?
Два способа глубокого копирования там для наглядности? Мне кажется, рекурсивно дергать MemberwiseClone будет куда быстрее полной сериализации. Не проверяли?
.
ВВ>Два способа глубокого копирования там для наглядности?
Нет, там только один способ глубокого копирования.
ВВ>Мне кажется, рекурсивно дергать MemberwiseClone будет куда быстрее полной сериализации.
Продемонстрируй, что ты имеешь в виду.
Здравствуйте, nikov, Вы писали:
ВВ>>Два способа глубокого копирования там для наглядности? N>Нет, там только один способ глубокого копирования.
Да, виноват. Мне показалось, способ с перебором полей делает примерно то же, что я предлагал.
ВВ>>Мне кажется, рекурсивно дергать MemberwiseClone будет куда быстрее полной сериализации. N>Продемонстрируй, что ты имеешь в виду.
Что-то типа такого. Не тестировал, чисто концептуальный пример:
public object Clone()
{
object copy = MemberwiseClone();
var mi = typeof(Object).GetMethod(
"MemberwiseClone", BindingFlags.NonPublic|BindingFlags.Instance);
Process(copy, mi);
return copy;
}
private void Process(object copy, MethodInfo mi)
{
var t = copy.GetType();
foreach (var f in t.GetFields(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance))
{
if (!f.FieldType.IsValueType && f.FieldType != typeof(String))
{
var fs = f.GetValue(copy);
if (fs != null)
{
var fun = (Func<Object>)Delegate.CreateDelegate(typeof(Object), fs, mi);
var fc = fun();
f.SetValue(copy, fc);
Process(fc, mi);
}
}
}
}
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Да, и, конечно же, надо проверять на рекурсивные ссылки
1) А зачем ты value types так обделил? Они, между прочим, тоже могут ссылаться на объекты.
2) Пропускаешь унаследованные private поля.
3) Как быть с массивами?
Здравствуйте, nikov, Вы писали:
N>1) А зачем ты value types так обделил? Они, между прочим, тоже могут ссылаться на объекты. N>2) Пропускаешь унаследованные private поля. N>3) Как быть с массивами?
Ну я же говорю чисто концептуальный пример Все это можно допилить. Проблемы с какими-то типами будут так или иначе (вроде пользовательских коллекций, в которых непонятно как можно менять элементы), но они же будут и у форматтера. А так по идее должно быть более производительной решение. И не требует от объекта быть сериализуемым.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, nikov, Вы писали:
N>>1) А зачем ты value types так обделил? Они, между прочим, тоже могут ссылаться на объекты. N>>2) Пропускаешь унаследованные private поля. N>>3) Как быть с массивами?
ВВ>Ну я же говорю чисто концептуальный пример Все это можно допилить.
Здравствуйте, nikov, Вы писали:
ВВ>>Ну я же говорю чисто концептуальный пример Все это можно допилить. N>Ну вот и вопросы чисто концептуальные.
Ну тогда чисто концептуальный ответ
private void Process(object parent, object copy, MethodInfo mi)
{
foreach (var f in GetFields(copy))
{
if (f.FieldType != typeof(String))
{
var fs = f.GetValue(copy);
if (Object.Equals(fs, copy) || Object.Equals(fs, parent))
continue;
if (fs is IList)
{
var lst = (IList)fs;
for (var i = 0; i < lst.Count; i++)
{
var newCopy = lst[i];
if (!newCopy.GetType().IsValueType)
lst[i] = newCopy = MakeFun(newCopy, mi)();
Process(copy, newCopy, mi);
}
}
else if (fs != null && !IsPrimitive(f.FieldType))
{
var newCopy = fs;
if (!f.FieldType.IsValueType)
f.SetValue(copy, newCopy = MakeFun(fs, mi)());
Process(copy, newCopy, mi);
}
}
}
}
private Func<Object> MakeFun(object obj, MethodInfo mi)
{
return (Func<Object>)Delegate.CreateDelegate(typeof(Func<Object>), obj, mi);
}
private IEnumerable<FieldInfo> GetFields(object obj)
{
var t = obj.GetType();
do
{
foreach (var f in t.GetFields(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance))
yield return f;
}
while ((t = t.BaseType) != default(Object));
}
//Это вообще необязательно или можно заменить на GetTypeCode, но работает быстрее и
//избавляет от ненужных "пробежек" по встроенным типамprivate bool IsPrimitive(Type type)
{
return typeof(Int32) == type || typeof(UInt32) == type || typeof(Int64) == type ||
typeof(UInt64) == type || typeof(Byte) == type || typeof(SByte) == type ||
typeof(Int16) == type || typeof(UInt16) == type || typeof(Single) == type ||
typeof(Decimal) == type || typeof(Double) == type || typeof(Double) == type ||
typeof(Char) == type || typeof(DateTime) == type;
}
ВВ>//Это вообще необязательно или можно заменить на GetTypeCode, но работает быстрее и
ВВ>//избавляет от ненужных "пробежек" по встроенным типам
ВВ>private bool IsPrimitive(Type type)
ВВ>{
ВВ> return typeof(Int32) == type || typeof(UInt32) == type || typeof(Int64) == type ||
ВВ> typeof(UInt64) == type || typeof(Byte) == type || typeof(SByte) == type ||
ВВ> typeof(Int16) == type || typeof(UInt16) == type || typeof(Single) == type ||
ВВ> typeof(Decimal) == type || typeof(Double) == type || typeof(Double) == type ||
ВВ> typeof(Char) == type || typeof(DateTime) == type;
ВВ>}
ВВ>