Laba diena,
Šoreiz runa ir par man personīgi neievērotu interfeisu, kas paskrējis ir netīšām garām laikā, kad Xml serializācija bija aktuāla projektā, pie kura strādāju.
Bija situācija, kad pa "drāti" tika pārraidīts objektu grafs, kas saturēja sevī uzvedību - t.i., atsevišķi lauki tika aprēķināti pēc atpakošanas.
Šim risinājumam bija gaiša doma, bet slikta realizācija. Izveidojām speciālas DTO (Data Transfer Objects) klases, kas tika plānotas kā datu pārnēsātāji, bet uzvedības - tikai kā konteineri. Datu pārnesātāju doma ir smuka - vienots kontrakts starp iesaistītajām pusēm, kas abstrahē lietotāju jeb iesaistīto pusi no implemntācijas detaļām otrā galā un ļauj vienoties kopējā saziņas interfeisā. Tomēr laiks gāja uz priekšu un viss šajā pasaulē ir nepastāvīgs, arī mūsu DTO objektu kopa apauga nedaudz ar loģiku, nedaudz ar uzvedību, kā rezultātā otrā "drāts" pusē DTO klientam jeb sistēmai nācās izsaukt dažādas palīdzības metodes, lai "restaurētu" objekta grafa sākotnējo stāvokli, kāds tas tika izveidots izsūtīšanas brīdī.
Tikai nesen pamanīju IDeserializationCallback intefeisu, kas ļotis smuki līmētos mūsu tā jau nedaudz pašķibajā arhitektūrā :)
Pielietojums ir pavisam vienkāršs.
Pieņemsim, ka objektu grafam, kas tiek pārraidīts pa drāti uz otru sistēmu ir lauki vai īpašības, kas nenonāk serializācijas rezultātā pārraidāmajās paciņās. Piemēram, kaut kādi izrēķināmie lauki, vai lauki, kurus var iegūt no objektu satura un netiek iekļauti serializācijā, lai samazinātu pārraidāmo datu apjomu.
Piemēram, klientam tas varētu būt personas koda pārbaudes rezultāts - vai kods, kas ir personai atbilst verifikācijas nosacījumiem vai nē. Šāda veida laukus var neiekļaut serializācijā par cik tie ir "izrēķināmie" lauki.
[Serializable]
public class Client
{
public Client()
{
}
public Client(string code)
{
this.Code = code;
this.IsValidCode = true;
}
public string Code { get; set; }
[XmlIgnore]
public bool IsValidCode { get; set; }
}
Pēc šāda objekta Xml serializācijas, ir redzams, ka IsValidCode atribūts netiek iekļauts kopējā pārraidājamā datu plūsmā.
Pēc šāda Xml dokuemtna saņemšanas un tā atpakošanas:
var deserializer = new XmlSerializer(cl.GetType());
object resultObj;
using (var reader = new StringReader(result))
{
resultObj = deserializer.Deserialize(reader);
}
kā redzams no klases izejas koda, IsValidCode atribūts klasei būs ar noklusēto vērtību = false. Šis gan varbūt nav pats veiksmīgākais piemērs, jo IsValidCode atribūta vērtību var noteikt mainot Code atribūta vērtību, bet pieņemsim, ka ir situācija, kur kāda atribūta vērtība ir jāizrēķina un tas nenotiek mainot citus klases atribūtus, bet gan vienreiz klases dzīves ciklā.
Protams, risinājums būtu iekļaut šo atribūtu arī serializācijas saturā, bet šeit varat pievērt otru aci :) Tagad gan būs jāatver vismaz vienai, lai varētu lasīt tālāk :)
Lai risinātu šāda veida problēmas, kad objekta grafa stāvoklis ir "jāatjauno" pēc sapakošanas/atpakošanas procedūras, ir pieejams IDeserializationCallback intefeiss, kas tie izmantots serializer klases ietvaros, lai nodotu ziņu par to, ka objekta grafs ir atpakots (deserializēts).
Interfeisa pielietošana nav sarežģīta.
[Serializable]
public class Client : IDeserializationCallback
{
public Client()
{
}
public Client(string code)
{
this.Code = code;
this.IsValidCode = true;
}
public string Code { get; set; }
[XmlIgnore]
public bool IsValidCode { get; set; }
public void OnDeserialization(object sender)
{
IsValidCode = true;
}
}
Kā redzams, tad ir nākusi klāt jauna metode OnDeserialization(object), kura tiek izsaukta uzreiz pēc tam, kad objektu lasītājs ir pabeidzis savu darbu.
Tomēr, jāpiemin, ka šī raksta tapšanas laikā atklājās, ka šis interfeiss darbojas tikai BinaryFormatter gadījumā, jo šis serializācijas veids izmanto ObjectManager klasi, kura implementē RaiseDeserializationEvent.
Arī izpētot un izdebugojot cauri XmlSerializer klases izsaukumu stekam, nekur nepamanīju šī jaukā intefeisa pielietojumu platformas kodā. Tā kā, Xml serializācijas gadījumā, būs vien jāizmanto kaut kādi pašdarinātie situācijas novēršanas paņēmieni.
Mūžu dzīvo, mūžu mācies :)
Cerams, ka noderēs!