параметр функции как ссылка
От: Аноним  
Дата: 17.12.09 18:33
Оценка:
как передавать в функцию копию объекта класса, а не ссылку на него.


 public void MyFunc(MyClass F)
        {
            ArrayList Array = new ArrayList();
            Array.Add(F);
            Array.Add(F);
        }


при изменении второго элемента Array[1] меняется значение Array[0].
как этого избежать?
Re: параметр функции как ссылка
От: meowth  
Дата: 17.12.09 18:40
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>как передавать в функцию копию объекта класса, а не ссылку на него.



А>
А> public void MyFunc(MyClass F)
А>        {
А>            ArrayList Array = new ArrayList();
А>            Array.Add(F);
А>            Array.Add(F);
А>        }
А>


А>при изменении второго элемента Array[1] меняется значение Array[0].

А>как этого избежать?

Вамм нужно клонировать F (если это не структура). Общего решения не существует. Частное -- склонировать приемлемым образом F и положить в массив вместо оригинального F.
... << RSDN@Home 1.2.0 alpha 4 rev. 1324>>
Re: параметр функции как ссылка
От: Spiceman  
Дата: 17.12.09 18:55
Оценка:
Здравствуйте, Аноним, Вы писали:

А>как передавать в функцию копию объекта класса, а не ссылку на него.


А что значит "копию"? Копии бывают разные.
Если класс содержит поля, которые ссылаются на экземпляры других классов, нужно ли чтобы в копии объекта поля ссылались на копии других классов?
Re: параметр функции как ссылка
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.12.09 16:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>при изменении второго элемента Array[1] меняется значение Array[0].

А>как этого избежать?

Посмотрите здесь
Автор: nikov
Дата: 10.06.07
.
Re[2]: параметр функции как ссылка
От: Воронков Василий Россия  
Дата: 18.12.09 16:22
Оценка:
Здравствуйте, nikov, Вы писали:

А>>при изменении второго элемента Array[1] меняется значение Array[0].

А>>как этого избежать?
N>Посмотрите здесь
Автор: nikov
Дата: 10.06.07
.


Два способа глубокого копирования там для наглядности? Мне кажется, рекурсивно дергать MemberwiseClone будет куда быстрее полной сериализации. Не проверяли?
Re[3]: параметр функции как ссылка
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.12.09 16:24
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

N>>Посмотрите здесь
Автор: nikov
Дата: 10.06.07
.


ВВ>Два способа глубокого копирования там для наглядности?

Нет, там только один способ глубокого копирования.

ВВ>Мне кажется, рекурсивно дергать MemberwiseClone будет куда быстрее полной сериализации.

Продемонстрируй, что ты имеешь в виду.
Re[4]: параметр функции как ссылка
От: Воронков Василий Россия  
Дата: 18.12.09 17:02
Оценка:
Здравствуйте, 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);            
            }
        }
    }
}
Re[5]: параметр функции как ссылка
От: Воронков Василий Россия  
Дата: 18.12.09 17:05
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


Да, и, конечно же, надо проверять на рекурсивные ссылки
Re[6]: параметр функции как ссылка
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.12.09 17:09
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Да, и, конечно же, надо проверять на рекурсивные ссылки


1) А зачем ты value types так обделил? Они, между прочим, тоже могут ссылаться на объекты.
2) Пропускаешь унаследованные private поля.
3) Как быть с массивами?
Re[7]: параметр функции как ссылка
От: Воронков Василий Россия  
Дата: 18.12.09 17:17
Оценка:
Здравствуйте, nikov, Вы писали:

N>1) А зачем ты value types так обделил? Они, между прочим, тоже могут ссылаться на объекты.

N>2) Пропускаешь унаследованные private поля.
N>3) Как быть с массивами?

Ну я же говорю чисто концептуальный пример Все это можно допилить. Проблемы с какими-то типами будут так или иначе (вроде пользовательских коллекций, в которых непонятно как можно менять элементы), но они же будут и у форматтера. А так по идее должно быть более производительной решение. И не требует от объекта быть сериализуемым.
Re[8]: параметр функции как ссылка
От: nikov США http://www.linkedin.com/in/nikov
Дата: 18.12.09 17:48
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, nikov, Вы писали:


N>>1) А зачем ты value types так обделил? Они, между прочим, тоже могут ссылаться на объекты.

N>>2) Пропускаешь унаследованные private поля.
N>>3) Как быть с массивами?

ВВ>Ну я же говорю чисто концептуальный пример Все это можно допилить.


Ну вот и вопросы чисто концептуальные.
Re[9]: параметр функции как ссылка
От: Воронков Василий Россия  
Дата: 18.12.09 18:32
Оценка:
Здравствуйте, 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;
}
Re[10]: параметр функции как ссылка
От: evi  
Дата: 20.12.09 13:36
Оценка: 8 (1)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>
ВВ>//Это вообще необязательно или можно заменить на 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;
ВВ>}
ВВ>


Можно задействовать http://msdn.microsoft.com/en-us/library/system.type.isprimitive.aspx
Re[11]: параметр функции как ссылка
От: Воронков Василий Россия  
Дата: 20.12.09 14:07
Оценка:
Здравствуйте, evi, Вы писали:

evi>Можно задействовать http://msdn.microsoft.com/en-us/library/system.type.isprimitive.aspx


Да, верно. Забыл об этом свойстве.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.