2009-09-03 12 views
7

Era tego, co chciałbym wiedzieć i skupić się na zrozumieniu, to szczegóły dotyczące deserializacji binarnej w środowisku Flex 3. Kiedy konstruktor jest wywoływany, gdy są ustawione właściwości, to prywatne serwery są serializowane lub występują wszystkie deserializacje na i przez seterów, itp? Mam trudności ze znalezieniem informacji na ten temat.W jaki sposób inicjuje się obiekt podczas deserializacji obiektów binarnych w środowisku Flex?

W aplikacji Flex 3 AIR mam dość złożony wykres obiektów (tylko kilka obiektów, które się do siebie odwołują, trochę jak duży model danych z wyjątkiem nieco bardziej złożonych), które serializuję do pliku za pomocą pojedynczego wywołania w obiekcie FileStream.writeObject i readObject na obiekcie głównym, który serializuje i deserializuje cały wykres obiektów.

Znalazłem, że potrzebuję zawsze mieć domyślny konstruktor, inaczej dostałbym wyjątki na obiektach podczas deserializacji, gdyby były częścią ArrayCollection. Musiałem więc wyeliminować parametry konstruktora lub ustawić domyślne wartości. Obecnie mam wiele takich seterów w moich klasach, na przykład poniżej, gdzie mConnection gromadzi pewne informacje, których potrzebuje poprzez różne setery, gdzie tak jak poprzednio miałem to wszystko zapakowane do konstruktora, ponieważ wszystkie informacje są naprawdę potrzebne do połączenia z funkcją :

class Client 
{ 
private var mConnection:Connection; 
public function get connection():Connection{ return mConnection; } 

public var mUser:User; 
public function get user():User { return mUser; } 
public function set user(value:User):void 
{ 
    mUser = value; 
    mConnection.username = user.username; 
    mConnection.password = user.password; 
} 

private var mServer:Server; 
public function get server():Server { return mServer;} 
public function set server(value:Server):void 
{ 
    mServer = value; 
    mConnection.serverIP = value.serverIP; 
} 

public function Client() 
{ 
    mConnection = new Connection(); 
} 
} 

public class Server 
{ 
[Bindable] 
public var Clients:ClientsCollection = new ClientsCollection();//contains Client type 
private var mServerIP:String; 
public function get serverIP():String { return mServerIP; } 
public function set serverIP(value:String):void 
{ 
    mServerIP = value; 
    serverName = mServerIP; 
} 

public var serverName:String; 

public function Server(serverIP:String = "") 
{ 
    this.serverIP = serverIP; 
} 
} 

Wydaje się to działać dobrze w większości przypadków, zanim dodałem do serializacji. Serializuję wykres obiektu po zamknięciu aplikacji i deserializuję go po otwarciu aplikacji. Co się stało

Po dodaniu serializacji, natknąłem się na problem, który po deserializacji, mConnection będzie czasami mieć pusty ciąg, a czasami będzie miał adres IP, który został serializowany. Najwyraźniej dzieje się tak, że czasami obiekty są deserializowane w innej kolejności, a następnie obiekty są przypisywane do właściwości w różnej kolejności. Powiedzmy, że w czasie, gdy serializuję wykres obiektów, mam instancję klienta, z odniesieniem do instancji serwera i połączenia, i jedną sekwencją zdarzeń podczas deserializacji (tylko jedno wywołanie readObject) może być :

  1. Połączenie jest skonstruowane.
  2. Właściwości połączenia są ustawiane z wartościami deserializowanymi.
  3. Serwer jest konstruowany z domyślnym konstruktorem (ma pusty ciąg dla serweraIP).
  4. Wartości serwerów są dezynfekowane i ustawione przez setery, przywracając serwerIP do "127.0.0.1" lub cokolwiek innego.
  5. Klient jest konstruowany
  6. Własność serwera klienta jest przypisana do wcześniej zbudowanej instancji serwera, co powoduje ustawienie wartości IP serwera połączenia za pomocą tej metody ustawiającej.

W tym scenariuszu połączenie ma poprawny adres IP serwera. Wydaje mi się, że wydaje się, że losowo, czasami dzieje się tak jednak, powodując, że identyfikator serwera połączenia jest pustym łańcuchem po zakończeniu deserializacji.

  1. Połączenie jest skonstruowane.
  2. Właściwości połączenia są ustawiane z wartościami deserializowanymi.
  3. Klient jest skonstruowany
  4. Server jest zbudowany z domyślnego konstruktora (ma pusty napis AdresIPSerwera)
  5. nieruchomość klient-serwer jest przypisany wcześniej skonstruowanego instancji serwera, przez co wartość AdresIPSerwera połączenia, który ma być ustawiony na pusty ciąg za pośrednictwem tego setera.
  6. Wartości serwerów są deserializowane i ustawiane za pomocą ustawiających, przywracając serwerIP do "127.0.0.1" lub cokolwiek innego.

Serwer IP połączenia jest nadal pustym ciągiem, ponieważ serwer został przypisany do właściwości klienta przed całkowitym zainicjowaniem serwera.

Prawdopodobnie mógłbym rozwiązać ten problem, używając wiązania, aby aktualizacje serwletu na serwerze były powiązane z połączeniem, ale uważam, że właściwości wiązania są dość skomplikowane (w Mxml jest to bardzo proste, ponieważ używasz tylko kręconych składnia nawiasów, ale robi to za pomocą kodu, co uważam za skomplikowane). Rozwiązałem także niektóre przypadki, całkowicie usuwając parametry konstruktora, więc nie ma wartości domyślnych. Odkładając to na bok, wciąż potrzebuję głębszego zrozumienia szczegółów serializacji binarnej, jeśli chodzi o odbudowywanie wykresu obiektów. Mam nawet odniesienia kołowe i wydaje mi się, że obsługuję te drobne i utrzymuję wiele odniesień bez duplikowania obiektów. To właśnie wtedy, gdy moje konstruktory/ustawiacze są bardziej skomplikowane, napotykam na te problemy z powodu kolejności występowania podczas deserializacji. Jest to jednak niespójne, ponieważ dodanie punktów przerwania w różnych miejscach wydaje się mieć wpływ na kolejność występowania rzeczy, co utrudnia debugowanie.

Na marginesie dla każdego, kto mógłby pominąć temat, ponieważ serializuję klasę o nazwie Połączenie. Dodałem trochę kodu, aby zaadresować niektóre rzeczy, na przykład w klasie Connection występuje instancja gniazda. Oczywiście moje gniazdo nie będzie połączone po zamknięciu i ponownym otwarciu aplikacji i deserializacji, więc zanim skończę serializować wykres obiektu, przechodzę i zamykam gniazdo i ustawiam referencję w klasie Połączenia na wartość null, tak, że nie ma dłuższe odwołanie do gniazda, a tym samym nie zostanie ono zserializowane. Po deserializacji przy następnym uruchomieniu aplikacji tworzę nowe gniazdo.

Odpowiedz

1

Coś na marginesie: można użyć funkcji statycznego jako konstruktor pseudo-przeciążony

class Fred 
{ 
    public function Fred() 
    { 
     // boring, default constructor with no parameters 
    } 

    public static function Freddy(aValue1 : String, aValue2 : Object = null) : Fred 
    { 
     var result : Fred = new Fred(); 

     result.value1 = aValue1; 
     result.value2 = aValue2; 

     return result; 
    } 
} 

(Tak, tęsknię moich Object Pascal wirtualnych konstruktorów, dlaczego pytasz?)

Powiązane problemy