11

Simple question: I understand that Serialization in C# requires default constructors. This would eliminate the possibility of using Constructor injected DI (which is generally the favored style of DI, in my reading[citation needed]). So is it really an either-or situation, or am I missing something?

(Side question): Do IoC containers side-step this tradeoff somehow?

kmote
  • 3,322
  • 6
  • 24
  • 33
  • `This would eliminate the possibility of using Constructor injected DI` -- Why? You can still have parameterized instructors, so long as you include a default constructor for serialization purposes (the default constructor can be private, if you like). – Robert Harvey Mar 18 '14 at 15:12
  • @RobertHarvey: I'm feeling a bit dense, but I don't quite get you. What's a "parameterized instructor"? (typo?) Once an object has been de-serialized, I can't construct it again. Are you suggesting I use property/setter injection on a default-consructed object? – kmote Mar 18 '14 at 15:19
  • 1
    A parameterized constructor is one with parameters. I'm assuming here that deserialization occurs from data that was derived from an object that was properly constructed using dependency injection. You don't have to construct the object during deserialization; *it was already constructed before.* – Robert Harvey Mar 18 '14 at 15:22
  • @RobertHarvey- OK. Lights are starting to come on. Perhaps I don't understand Serialization properly. I want to instantiate my objects based on a detailed xml configuration file. I thought I could get boost by using the built in Serialization tools. So for my purposes, nothing has been constructed before -- it's just been defined in an xml file. I was hoping that Serialization could automatically instantiate my objects, assuming I set up the xml file properly. Am I mistaken here? – kmote Mar 18 '14 at 15:28
  • 1
    No, you're not mistaken. That's how it works. Think of it as back-door injection. You won't get any validation, but it will work. Note that BinaryFormatter and DataContractSerializer do not require default constructors. – Robert Harvey Mar 18 '14 at 15:31
  • 1
    To be clear, all deserialization does is fill the state in your object with the values that are specified in the XML object. It uses Reflection to accomplish this, and bypasses any form of constructor validation logic, so from the perspective of DI, it is cheating, unless those XML values originally came from an object constructed through ordinary DI. – Robert Harvey Mar 18 '14 at 15:35
  • Which is exactly what you want, as the logic used to in the parameterised constructors and/or getters and setters might change the state of the object from what it would be when reconstructed like that. Mind that that's not necessarilly a good design but it's common to have a getter do "something" to its input parameters. – jwenting Mar 18 '14 at 15:51

2 Answers2

8

It is not possible to de-serialize an object and also inject a dependency to another, already existing object, in one step in C#, using the standard serialization mechanisms. You will have to use property injection instead, first constructing the object using the deserializer, afterwards injecting the dependency. For most real-world applications, I don't consider this beeing a real drawback - if you have a serializeable data model class, which has also dependencies to other, non-data model classes, you should check if your data model class may have too many responsibilities already.

If that really bothers you, you may consider to wrap your serializable object with a decorator class, where you can pass the de-serializer and additional dependencies through the constructor. That wrapper then executes the two steps (de-serialization of the wrapped object and property injection) in its constructor.

Doc Brown
  • 199,015
  • 33
  • 367
  • 565
1

I'm solving this problem like that: injecting factories of dependencies. In those factories, first resolve dependency as it is registered in container, then "deserializing" all remaining data: json.net allows to populate fields in existing object.

As factories code goes along with wiring code of IoC container, I don't think using container.Resolve inside factory violates the rule, that container have to be used just in one place in code: where all wiring happens.

As of now, I'm trying to make this process automatic (as opposed to what I've been testing that approach at) using reflection. Yes, there is not much what does remain from json.net deserialization itself, part of it is substituted with custom code, but I think, why bother.

Also, what was your final thoughts/decision on the matter? After reading this post i see two ways: deserialize, then inject; or inject, then deserialize (populate). And i still find my way is better. Will be glad to hear arguments in opposition to this (i'm regarding, that my way may be better for my case, but can't vividly imagine good alternative cases, where it fails, just some minor guesses)

jungle_mole
  • 381
  • 1
  • 3
  • 11