[C#] Jak skopiować obiekt

0

Pytanie początkującego:Jak najprościej (bez dużej ilości kodu) "skopiować" obiekt danej klasy. Chodzi mi o to, żeby móc operować na kopii nie wpływając na obiekt pierwotny. Łatwiej mi będzie zrozumieć na przykładzie, tak więc (przykład został mocno okrojony dla przejrzystości):

  
public class track 

    {
        public List<int> order = new List<int>();
    }

        private track opt(track opt_track)
        {
            track old_track = opt_track;
            old_track.order.Reverse(); // i tu mi odwróci kolejność oczywiście w obydwu obiektach
            return old_track;
        }

Więc pytanko oczywiście jak to zrobić, żeby odwrócił mi wartości tylko w old_track, zostawiając opt_track w spokoju. O referencji coś tam wiem, ale zawsze mam tego typu problemy. Proszę tylko o tłumaczenie w sposób zrozumiały dla zielonych. Z góry dzięki.

0

Się zastanawiam co to za zmienna ten "track", a to u Ciebie klasa. Weź pisz nazwy klas wielką literą, będzie łatwiej czytać.

Jak rozumiem chcesz sklonować swój obiekt. Najprościej chyba użyć w tym celu serializacji binarnej, czyli np umieścić taką metodę w klasie Track:

public Track Clone()
{
	using (MemoryStream ms = new MemoryStream())
	{
		BinaryFormatter bf = new BinaryFormatter();
		bf.Serialize(ms, this);
		ms.Seek(0, SeekOrigin.Begin);
		return bf.Deserialize(ms);
	}
}
0

Można by też trochę prościej:

    class Person
    {
        public string imie;
        public int wiek;

        public Person(Person person)
        {
            this.imie = person.imie;
            this.wiek = person.wiek;
        }

        public Person()
        {
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<Person> ludzie = new List<Person>
            {
                new Person(), new Person(), new Person()
            };

            List<Person> ludzieKopia = new List<Person>();
            ludzie.ForEach(x => ludzieKopia.Add(new Person(x)));
            ludzie[0].imie = "Jan";
            ludzie[0].wiek = 35;

            Console.WriteLine(ludzieKopia[0].imie);
            Console.WriteLine(ludzieKopia[0].wiek);
        }
    }
0

http://www.csharp411.com/c-object-clone-wars/

Różne sposoby kopiowania obiektów.
Chyba najprostszy to implementacja dla danej klasy - interfeju ICloneable

0

@ozi88 - jeśli dodasz nowe pole czy właściwość w klasie, to będziesz musiał zmienić swoją metodę. Ja swojej nie będę musiał.
@dark_astray:

  1. Implementowanie ICloneable to rozwiązanie do d**y, bo po pierwsze Clone zwraca nieładny typ object, a po drugie nie wiadomo, czy ma zwracać kopię płytką czy głęboką, czy w takim przypadku dla drugiego typu kopii trzeba robić inną metodę i jaką ją nazwać, itd., itp. Ktoś korzystający z tego niekoniecznie będzie wiedział co ta metoda zwraca.
    Poza tym, żeby zaimplementować trzeba mieć pomysł jak to zrobić. Ty go jakoś nie podałeś, więc czemu piszesz, że to najprostsze?
0

Jaki problem zrobić sobie własny interfejs..

    interface ICopyable<T>
    {
        T ShallowCopy();
        T DeepCopy();
    }

albo dać sobie spokój z interfejsem i po prostu zaimplementować te metody.

0
somekind napisał(a)

Ty go jakoś nie podałeś, więc czemu piszesz, że to najprostsze?

Jest w linku ktory podałem... zerknij.

0

@Azarien - oczywiście żaden. Ale własny, to nie jest już ICloneable, nie? ;)

@dark_astray - Ty piszesz, że najprościej zaimplementować metodę Clone, a w linku jest kilka sposobów implementacji tej metody. Więc jak w końcu? ;P

0

Konkretnie chodziło mi o ten sposob z memberwiseClone.
W linku jest kilka sposobów na skopiowanie obiektu. Kolega na początku pisze że jest początkujący, a implementacja ICloneable z memberwiseclone to nie jest problem, jak widać. Nie twierdze że najlepszy sposób, bo wcale taki nie jest, ale jest prosty.
Niepotrzebna dyskusja.

0

Ale MemberwiseClone nie działa dla typów referencyjnych, prawda? A kolega początkujący może o tym nie wiedzieć, coś mu nie będzie działało i nie będzie wiedział dlaczego. ;)

0

somekind właśnie o coś takiego mi chodziło. W każdym razie wielkie dzięki wszystkim za sugestie. Ta metoda jest dla mnie najbardziej użyteczna, bo nie muszę jej poprawiać jak mi dojdzie coś w klasie, poza tym jest najkrótsza (klasa jest trochę złożona).
Ale mam jeszcze jedno pytanko. tutaj znalazłam coś na ten temat i piszą że można napisać metodę, która serializuje wszystkie obiekty. Nie ukrywam, że byłoby to dla mnie świetne wyjście, bo nie muszę pisać osobnej metody dla każdej klasy. Czy taka metoda ma sens? Rozumiem, że wtedy muszę każdą funkcję oznaczyć atrybutem Serializable? A jak to jest w przypadku typów wbudowanych, tzn. czy mogę jej używać do zwykłych tablic, list itp. ?
Poniżej kod proponowanej metody, jakby się komuś nie chciało zaglądać.

public static T CloneObject<T>( T item )
{
   using ( MemoryStream ms = new MemoryStream() )
   {
      //instancja BinaryFormattera - informujemy go,
      //ze bedzie uzyty w celu klonowania
      BinaryFormatter bf = new BinaryFormatter(null, 
                new StreamingContext(StreamingContextStates.Clone));
                
      //serializacja
      bf.Serialize(ms, item);

      //przewijamy memoryStream do poczatku
      ms.Seek(0, SeekOrigin.Begin);

      //deserializacja
      return ( T )bf.Deserialize(ms);
   }
}

//i użycie
Person kowalskiCopy = Tools.CloneObject<Person>(kowalski);

Debug.Write(kowalski.Boss == kowalskiCopy.Boss);
0

Ta metoda, to moja propozycja w wersji extension i generic. Wielkich czarów tu nie ma. :)
Ale zadziała tylko z klasami z atrybutem Serializable. Chyba większość standardowych klas ma ten atrybut, więc z nimi też będziesz mógł jej użyć.

0

jak mozna (i czy da sie w ogóle?) kopie obiektu HttpWebRequest?
np. definicja klasy httpwebrequest jest taka:

[SerializableAttribute]
public class HttpWebRequest : WebRequest, 
	ISerializable

mimo to klasy nieda sie serializowac
Typ 'System.Net.WebRequest+WebProxyWrapper' w zestawie 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' nie jest oznaczony jako możliwy do serializacji.
[???]

jak można zatem utworzyc kopie tego obiektu i czy <ort>w ogóle </ort>da sie?

0

Napisałem kiedyś pełne klonowanie używając Refleksji.

Oto kod: http://pastebin.com/f713584a

Powinno działać...

0
Deti napisał(a)

Napisałem kiedyś pełne klonowanie używając Refleksji.

Oto kod: http://pastebin.com/f713584a

Powinno działać...

dzieki coś w tym stylu własnie byłoby potrzebne ale
nie działa ponieważ HttpWebRequest nie ma konstruktorów zedfiniowanych:

object toret=Activator.CreateInstance(obj.GetType()); //MissingMethodException
Dla tego obiektu nie zdefiniowano konstruktora bez parametrów.
0

Skoro ani serializacja ani refleksja nie chce zadziałać, to chyba zostaje ostateczność i klonowanie ręczne.
Ewentualnie można jeszcze przemyśleć zagadnienie - może da się rozwiązać problem inaczej niż przez klonowanie obiektu?

0

tak problem da się rozwiązac inaczej i tak tez zrobie chodzi tolko o to aby przekopiowac wartości właściwości z jednego httpwebrequest do nowego poniewaz ciągle sa resetowane gdy sie tworzy instancje dla każdego Uri osobno... napisałem funkcje kopiujaca wlasciwosci pomiędzy dwoma obiektami ale właśnie z powodu braku mozliwości utworzenia klona HttpWebRequest funkcja nie działa dla tego obiektu, dla innych klas tak, ale cóż dam rade dzieki

1 użytkowników online, w tym zalogowanych: 0, gości: 1