Serializace
Moderátor: Caleb
Serializace
Kdyby nekdo bojoval se serializaci, tak tady je pekny navod, ze ktereho jsem se to ted naucil:
http://www.switchonthecode.com/tutorial ... -to-a-file
K cemu je serializace dobra? Umozni mi do souboru ulozit rovnou cely objekt. Priklad: chci si nekam zaznamenat List<Waypoint>, ktery obsahuje udaje o souradnich, nasledujicich a predchozich waypointech. Nemuzu ho jentak ulozit do souboru, protoze bych pak mel hodne starosti s nacitanim. Musel bych totiz data ukladat jako string a v urcitem formatu, abych je zpetne dokazal nacist. Tak jsem to alespon pochopil :p Takze jsem si nasel tenhle navod a podle nej mohu serializovat tridu pro waypoint a pak pro samotny list waypointu. Diky tomu jsem schopny ulozit cely list do souboru a zpetne ho nacist a rovnou pouzivat.
http://www.switchonthecode.com/tutorial ... -to-a-file
K cemu je serializace dobra? Umozni mi do souboru ulozit rovnou cely objekt. Priklad: chci si nekam zaznamenat List<Waypoint>, ktery obsahuje udaje o souradnich, nasledujicich a predchozich waypointech. Nemuzu ho jentak ulozit do souboru, protoze bych pak mel hodne starosti s nacitanim. Musel bych totiz data ukladat jako string a v urcitem formatu, abych je zpetne dokazal nacist. Tak jsem to alespon pochopil :p Takze jsem si nasel tenhle navod a podle nej mohu serializovat tridu pro waypoint a pak pro samotny list waypointu. Diky tomu jsem schopny ulozit cely list do souboru a zpetne ho nacist a rovnou pouzivat.
Re: Serializace
V principu serializace = uložení objektu do stringu/binární podoby, aby to šlo pak zpětně deserializovat.
Můžeš např. vzít pole waypointů, serializovat je do souboru, poslat někomu, ten to ve svým scriptu deserializuje a má zpátky původní pole. Nic víc, nic míň
Smysl to má pokud např. máš nějaký runtime nastavení nebo hodnoty, např. něco co si naklikáš ve hře, a chceš aby ti to zůstalo i po tom co tu app vypneš.
Můžeš např. vzít pole waypointů, serializovat je do souboru, poslat někomu, ten to ve svým scriptu deserializuje a má zpátky původní pole. Nic víc, nic míň
Smysl to má pokud např. máš nějaký runtime nastavení nebo hodnoty, např. něco co si naklikáš ve hře, a chceš aby ti to zůstalo i po tom co tu app vypneš.
Re: Serializace
Resim problem ohledne serializace, snad. Pridam si par waypointu, ulozim si je do souboru, zkusim je ze souboru nacist - ok. Relognu. Zkusim waypointy nacist ze souboru a dostanu: "Error: Runtime error: Sestavení gout1_1b, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null nebylo nale". Kdyz to zkusim jeste jednou potom loadnout, tak to vypise chybu o pretypovani. Takova tam ale neni, jinak by to neslo spustit napoprve.
E: cela chyba
E2: Chapu, ze je to asi problem ruznych assembly, zkusil jsem pouzit neco generickeho pres , ale to nejak neklaplo. Zkousel jsem Binder, ale to mi take nepomohlo. Z toho, co ctu je nejspis problem, ze pouzivam svuj vlastni list s vlastnimi objekty.
E3: ok, assembly format pro serializaci a deserializaci mam nastaveny na simple, binder mam upraveny tak, ze dokaze najit spravnou assembly a jeji typ sikovne podstrcit dal, ale narazil jsem na problem s pretypovanim, ktery to hlasi... asi jelikoz je rozdil v assembly, tak to neni schopne castnout :/
E: cela chyba
Kód: Vybrat vše
02:26 Phoenix: System.Runtime.Serialization.SerializationException: Sestavení f_6uuj8g, Version=0.0.0.0, Culture=ne
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assembly
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memb
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.ObjectMap.Create(String name, String[] memberNam
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObje
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHead
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler,
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serialization
02:26 Phoenix: v System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serialization
02:26 Phoenix: v Phoenix.Scripts.Serializer.DeSerializeObject(String filename)
Kód: Vybrat vše
bFormatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
E3: ok, assembly format pro serializaci a deserializaci mam nastaveny na simple, binder mam upraveny tak, ze dokaze najit spravnou assembly a jeji typ sikovne podstrcit dal, ale narazil jsem na problem s pretypovanim, ktery to hlasi... asi jelikoz je rozdil v assembly, tak to neni schopne castnout :/
Re: Serializace
BinaryFormatter ukládá přesný info o assembly která serializaci prováděla a při deserializaci zase tu přesně stejnou assembly hledá. Skripty se ti pokaždé kompilujou znova -> není to úplně ta samá assembly -> nebude ti to fungovat. Netušim jestli se to dá nějak obejít, asi jo, ale ne jednoduše.
Každopádně bych řek, že s tym budeš mít takdle akorát zbytečný sraní a bude to zbytečně složitý Navíc ten BinaryFormatter není zrovna nejrychlejší.
Nejjednoduší asi Nebo prostě do XML, přes System.Xml.Linq (XDocument, XElement, ...) je to podobně jednoduchej kód. Záleží co ukládáš a co s tym chceš dělat, že jo. Jestli chceš mít možnost to měnit i bez spuštěnýho programu přímo v souboru tak XML (třeba abys kvůli jednomu waypointu nemusel nahrávat všechno znova od začátku), jestli je to jedno tak první možnost no.
Každopádně bych řek, že s tym budeš mít takdle akorát zbytečný sraní a bude to zbytečně složitý Navíc ten BinaryFormatter není zrovna nejrychlejší.
Kód: Vybrat vše
//Save
List<WayPoint> wayPoints = new List<WayPoint>();
using (BinaryWriter writer = new BinaryWriter(File.Open("WayPoints", FileMode.Create, FileAccess.Write)))
foreach (WayPoint wayPoint in wayPoints)
{
writer.Write(wayPoint.X);
writer.Write(wayPoint.Y);
writer.Write(wayPoint.Z);
}
//Load
List<WayPoint> wayPoints = new List<WayPoint>();
using (BinaryReader reader = new BinaryReader(File.Open("WayPoints", FileMode.Open, FileAccess.Read)))
while (reader.PeekChar() != -1)
wayPoints.Add(new WayPoint(reader.ReadUInt16(), reader.ReadUInt16(), reader.ReadUInt16()));
http://dl.dropbox.com/u/36197238/Phoenix/Phoenix.Scripts.DP.7z
Re: Serializace
Jsem ve stavu, kdy dokazi identifikovat assembly, ve ktere bylo serializovano, ale nejsem schopny ji nacist tak, aby nedoslo k jejimu zdvojeni, proto mi to pak nejde pretypovat, protoze ackoliv jsou ty assembly stejne, nejsou identicke. Mozna se to tyka LoadFrom a LoadFile metod a vytvareni instanci assembly.
XML si nechavam az jako zalohu, tohle mi prislo jako docela zajimavy problem, tak jsem se do toho zakousnul Dik za kod, dost mozna u neceho podobneho skoncim. By me nenapadlo, ze to bude tak pomotane
Jdu na tu Tvou alternativu, tohle me fakt zklamalo Akorat je problem, ze ja neukladam jen x, y, z, ale i prev a next Waypoint ^^ Bude to vypadat asi trochu strasidelne.
E: aby peekChar nevyhazoval chybu, musel jsem upravit tohle:
E2: Vse jiz funguje, jen me mrzi, ze to neni presne to reseni, ktere jsem chtel Diky za pomoc
XML si nechavam az jako zalohu, tohle mi prislo jako docela zajimavy problem, tak jsem se do toho zakousnul Dik za kod, dost mozna u neceho podobneho skoncim. By me nenapadlo, ze to bude tak pomotane
Kód: Vybrat vše
sealed class AllowAllAssemblyVersionsDeserializationBinder : System.Runtime.Serialization.SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
try
{
string ToAssemblyName = assemblyName.Split(',')[0];
//UO.Print("co hledam: {0}",ToAssemblyName);
Assembly[] Assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly ass in Assemblies)
{
//UO.Print(ass.FullName.Split(',')[0]);
if (ass.FullName.Split(',')[0] == ToAssemblyName)
{
typeToDeserialize = ass.GetType(typeName);
break;
}
}
} catch (System.Exception exception)
{
throw exception;
}
return typeToDeserialize;
}
}
E: aby peekChar nevyhazoval chybu, musel jsem upravit tohle:
Kód: Vybrat vše
using (BinaryReader reader = new BinaryReader(new System.IO.FileStream(path, FileMode.Open, FileAccess.Read),Encoding.ASCII))
Re: Serializace
Když už sis s tym takdle vyhrál.
V tom kódu cos postnul - neměl bys brat ten Type z assembly co právě používáš než z té ve které si to serializoval?
Tzn. prostě
Tim co si udělal najdeš ten původní Type (+ teda jen dokavaď to celý nevypneš) a ten samozřejmě nejde přetypovat na ten Type co máš teď nově zkompilovanej.
V tom kódu cos postnul - neměl bys brat ten Type z assembly co právě používáš než z té ve které si to serializoval?
Tzn. prostě
Kód: Vybrat vše
public override Type BindToType(string assemblyName, string typeName)
...
Assembly assembly = Assembly.GetExecutingAssembly();
typeToDeserialize = assembly.GetType(typeName);
...
http://dl.dropbox.com/u/36197238/Phoenix/Phoenix.Scripts.DP.7z
Re: Serializace
Zkusil jsem to a myslim, ze to ani fungovat nemuze, nebo jsem Ti nerozumel.
Nelze pretypovat. Neco podobneho jsem zkousel driv, se stejnym vysledkem.
Je pravda, ze do predminuleho tydne jsem Cecko nevidel, takze je dost mozne, ze tohle vsechno je zpusobene jen mou nezkusenosti. Uz jenom to, ze jsem nepouzil rovnou XMLSerializer, ktery by mi podle me dost usnadnil praci. Alespon se to tak tvari: http://mfharoon.blogspot.cz/2006/12/usi ... e-not.html
Kód: Vybrat vše
sealed class AllowAllAssemblyVersionsDeserializationBinder : System.Runtime.Serialization.SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
try
{
Assembly assembly = Assembly.GetExecutingAssembly();
typeToDeserialize = assembly.GetType(typeName);
} catch (System.Exception exception)
{
throw exception;
}
return typeToDeserialize;
}
}
Kód: Vybrat vše
string currentAssembly = Assembly.GetExecutingAssembly().FullName;
typeToDeserialize = Type.GetType(string.Format("{0}, {1}", typeName, currentAssembly));
Re: Serializace
Kód: Vybrat vše
public class CoolBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
int index = typeName.IndexOf(", Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
if (index != -1)
{
typeName = typeName.Remove(index - 8, 8);
typeName = typeName.Insert(index - 8, typeof(CoolBinder).Assembly.GetName().Name);
}
return Type.GetType(typeName);
}
}
Todle i funguje, jen to není úplně čistá cesta no Ale nevim jak jinak zjistit jméno tej původní assembly...
http://dl.dropbox.com/u/36197238/Phoenix/Phoenix.Scripts.DP.7z
Re: Serializace
Jmeno puvodni assembly je v assemblyName, to neni problem zjistit:
Ale ziskat pak odkaz na tu puvodni assembly mi prijde lehce imposibru.
Kód: Vybrat vše
public override Type BindToType(string assemblyName, string typeName)
...
string ToAssemblyName = assemblyName.Split(',')[0];
Re: Serializace
Když deserializuješ List<WayPoint>, tak se poprvé BindToType volá právě pro ten list - assemblyname je "mscorlib, blablabla" (tzn ne jméno původní assembly, ale assembly ve které je ten list), typename je zhruba "system.blabla.list[blablabla.WayPoint[tadytoděsnýinfoopůvodníassembly]]" -> musíš v tom typename najít jméno tej původní assembly, vyměnit za tu aktuální (tak jak sem to udělal vejš)
Až podruhé se to volá pro ten samotnej waypoint, tam už je v assemblyname ta původní assembly, to ti je ale už k ničemu.
To co sem hodil vejš funguje, jen to nevypadá úplně pěkně
Až podruhé se to volá pro ten samotnej waypoint, tam už je v assemblyname ta původní assembly, to ti je ale už k ničemu.
To co sem hodil vejš funguje, jen to nevypadá úplně pěkně
http://dl.dropbox.com/u/36197238/Phoenix/Phoenix.Scripts.DP.7z
Re: Serializace
Diky za vysvetleni, ted uz tomu rozumim. A dik za kodCarda píše:Když deserializuješ List<WayPoint>, tak se poprvé BindToType volá právě pro ten list - assemblyname je "mscorlib, blablabla" (tzn ne jméno původní assembly, ale assembly ve které je ten list), typename je zhruba "system.blabla.list[blablabla.WayPoint[tadytoděsnýinfoopůvodníassembly]]" -> musíš v tom typename najít jméno tej původní assembly, vyměnit za tu aktuální (tak jak sem to udělal vejš)
Až podruhé se to volá pro ten samotnej waypoint, tam už je v assemblyname ta původní assembly, to ti je ale už k ničemu.
To co sem hodil vejš funguje, jen to nevypadá úplně pěkně
Re: Serializace
Takdle je to asi lepší
Kód: Vybrat vše
public class CoolBinder : SerializationBinder
{
//při serializaci změnit jméno assembly na vlastní
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = serializedType.Assembly.FullName;
typeName = serializedType.FullName.Replace(typeof(CoolBinder).Assembly.GetName().Name, "ScriptAssembly");
}
//při deserializaci změnit vlastní jméno zpátky na aktuální
public override Type BindToType(string assemblyName, string typeName)
{
typeName = typeName.Replace("ScriptAssembly", typeof(CoolBinder).Assembly.GetName().Name);
return Type.GetType(typeName);
}
}
http://dl.dropbox.com/u/36197238/Phoenix/Phoenix.Scripts.DP.7z
Re: Serializace
To uz vypada mnohem lepe Super!