{"action":"created","issue":{"url":"https://api.github.com/repos/simpleinjector/SimpleInjector/issues/196","repository_url":"https://api.github.com/repos/simpleinjector/SimpleInjector","labels_url":"https://api.github.com/repos/simpleinjector/SimpleInjector/issues/196/labels{/name}","comments_url":"https://api.github.com/repos/simpleinjector/SimpleInjector/issues/196/comments","events_url":"https://api.github.com/repos/simpleinjector/SimpleInjector/issues/196/events","html_url":"https://github.com/simpleinjector/SimpleInjector/issues/196","id":137665128,"number":196,"title":"Q: Understanding complex injection","user":{"login":"CaninChristell","id":12700701,"avatar_url":"https://avatars.githubusercontent.com/u/12700701?v=3","gravatar_id":"","url":"https://api.github.com/users/CaninChristell","html_url":"https://github.com/CaninChristell","followers_url":"https://api.github.com/users/CaninChristell/followers","following_url":"https://api.github.com/users/CaninChristell/following{/other_user}","gists_url":"https://api.github.com/users/CaninChristell/gists{/gist_id}","starred_url":"https://api.github.com/users/CaninChristell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CaninChristell/subscriptions","organizations_url":"https://api.github.com/users/CaninChristell/orgs","repos_url":"https://api.github.com/users/CaninChristell/repos","events_url":"https://api.github.com/users/CaninChristell/events{/privacy}","received_events_url":"https://api.github.com/users/CaninChristell/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-03-01T19:34:30Z","updated_at":"2016-03-02T03:42:27Z","closed_at":null,"body":"I've been Googling around on this issue and haven't come across any clear explanation of how-to with complex conditional injection. One of the common concerns voiced is that one is not fulfilling the Liskov Substitution Principle, but I don't believe that's the case with this design.\r\n\r\n(I have viewed the [documentation on the subject](https://simpleinjector.readthedocs.org/en/latest/advanced.html#context-based-injection), but either I'm not understanding it, or it's addressing a different concern)\r\n\r\nSay that you have the interface IDataReader(T), and the concrete implementations CacheReader(T), MongoReader(T), SqlServerReader(T), and OracleReader(T). All have a simple method that takes an ID (let's say always an int), and returns T. Several business logic classes depend on IDataReader(T), and let's say that's fulfilled by CacheReader(T) (with the freedom to change this choice in the future). CacheReader itself also depends on another IDataReader(T). This dependency might be on any of the three other implementations of IDataReader, which is defined using SimpleInjector at compile type (not dynamically). \r\n\r\nHow, then, would you specify: \r\n\r\n> When ConcreteA depends on IDataReader(T), use CacheReader(T), and for CacheReader(T)'s dependency on IDataReader(T), use MongoReader(T)\r\n> When ConcreteB depends on IDataReader(T), use CacheReader(T), and for CacheReader(T)'s dependency on IDataReader(T), use SqlServerReader(T)\r\n> When ConcreteC depends on IDataReader(T), use CacheReader(T), and for CacheReader(T)'s dependency on IDataReader(T), use OracleReader(T)\r\n> When ConcreteD depends on IDataReader(T), use CacheReader(T), and for CacheReader(T)'s dependency on IDataReader(T), use OracleReader(T)\r\n\r\nAgain, I don't think this is violating LSP as all of the IDataReader(T)s fulfill the programmatic requirements (return T given an ID of _) and externally viewed none of them behave differently; CahceReader could be removed and have Concrete[A,B,C] depend directly on a data storage implementation of IDataReader(T), and Concrete[A,B,C] should not be able to tell the difference.\r\n\r\nThe only issue, then, is if the ultimate storage technology houses the desired information, which I don't think should be the concern of the code architecture or injection.\r\n\r\nI apologize if this was wordy, I was just trying to provide clarity to my lack of understanding, and state what I've worked through/thought through.\r\n\r\n**Edit: The generic type notations weren't appearing, so I changed all of them from angle brackets to parenthesis marks.**"},"comment":{"url":"https://api.github.com/repos/simpleinjector/SimpleInjector/issues/comments/191042289","html_url":"https://github.com/simpleinjector/SimpleInjector/issues/196#issuecomment-191042289","issue_url":"https://api.github.com/repos/simpleinjector/SimpleInjector/issues/196","id":191042289,"user":{"login":"CaninChristell","id":12700701,"avatar_url":"https://avatars.githubusercontent.com/u/12700701?v=3","gravatar_id":"","url":"https://api.github.com/users/CaninChristell","html_url":"https://github.com/CaninChristell","followers_url":"https://api.github.com/users/CaninChristell/followers","following_url":"https://api.github.com/users/CaninChristell/following{/other_user}","gists_url":"https://api.github.com/users/CaninChristell/gists{/gist_id}","starred_url":"https://api.github.com/users/CaninChristell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CaninChristell/subscriptions","organizations_url":"https://api.github.com/users/CaninChristell/orgs","repos_url":"https://api.github.com/users/CaninChristell/repos","events_url":"https://api.github.com/users/CaninChristell/events{/privacy}","received_events_url":"https://api.github.com/users/CaninChristell/received_events","type":"User","site_admin":false},"created_at":"2016-03-02T03:42:27Z","updated_at":"2016-03-02T03:42:27Z","body":"Thank you for the reply, Steven! I think I follow the logic up until the\n!c.Handled part. What is that accomplishing, and why?\n\nAs far as the LSP; as long as the various data storage technologies were\nupholding the contract of storing (and returning) type T then nothing\nshould break, and thus Concrete[A,B,C,D] shouldn't care if they are being\nfulfilled by whichever IDataReader; the code itself is LSP. It'd be up to\nthe programmer to ensure he was injecting dependencies properly based on\nwhere the items actually were being stored, and adjusting the injection if\nthe storage choices changed. Since the chance of code breakage would be\nstrictly outside the actual code itself (including the data access), and\ndependent on the storage itself (the data) fulfilling an imposed contract,\nwouldn't this be a LSP sound design?\n\nI feel as though it is LSP sound, as it accomplishes the code-side promises\nand consistency that LSP is trying to enforce. And this solution allows,\nsay, Product and ProductDetails to move from Mongo to Oracle by only\nchanging the injection (and a new concrete that fulfills the interface) and\nleaving absolutely all of the existing code untouched, thus abiding by the\nOpen Close Principle.\n\nIs that all correct? I'm new to actually trying to implement SOLID (thus\nwhy I'm trying to work through the logic of dependency injectors) so these\nconcepts are fairly new to me.\n\nOn Tue, Mar 1, 2016 at 7:00 PM, Steven <notifications@github.com> wrote:\n\n> Hi @CaninChristell <https://github.com/CaninChristell>,\n>\n> @dadhi <https://github.com/dadhi> is right, your CacheReader<T> is a\n> decorator. So for convenience, let's rename it to CacheReaderDecorator.\n>\n> So if I understand correctly, these are the object graphs you wish to\n> build:\n>\n> new ConcreteA(\n>     new CacheReaderDecorator<T>(\n>         new MongoReader<T>()))\n>\n> new ConcreteB(\n>     new CacheReaderDecorator<T>(\n>         new SqlServerReader<T>()))\n>\n> new ConcreteC(\n>     new CacheReaderDecorator<T>(\n>         new OracleReader<T>()))\n>\n> new ConcreteD(\n>     new CacheReaderDecorator<T>(\n>         new OracleReader<T>()))\n>\n> You can achieve this by using the following configuration;\n>\n> container.RegisterConditional(typeof(IDataReader<>), typeof(MongoReader<>),\n>     c => c.Consumer.ImpementationType == typeof(ConcreteA));\n> container.RegisterConditional(typeof(IDataReader<>), typeof(SqlServerReader<>),\n>     c => c.Consumer.ImpementationType == typeof(ConcreteB));\n> container.RegisterConditional(typeof(IDataReader<>), typeof(OrackeReader<>),\n>     c => !c.Handled);\n>\n> container.RegisterDecorator(typeof(IDataReader<>), typeof(CacheReaderDecorator<>));\n>\n> I don't think this is violating LSP as all of the IDataReader(T)s fulfill\n> the programmatic requirements (return T given an ID of _) and externally\n> viewed none of them behave differently;\n>\n> Whether or not the implementations use the same abstraction is irrelevant\n> for adhering to the LSP. Instead you should ask yourself what would happen\n> to your application if you supply say for instance ConcreteA with an\n> OracleReader instead of a MongoReader. Would that break ConcreteA at\n> runtime or would it keep functioning correctly?\n>\n> If ConcreteA would keep functioning correctly (e.g. no exception is\n> thrown), you adhere to the LSP. But in case it would break ConcreteA, you\n> are in fact violating the LSP, since clearly the implementations of\n> IDataReader behave in an incompatible way (since LSP states that\n> implementations should be interchangeable). The contract of an interface\n> consists not only of its method signature; it consists of its behavior as\n> well; this behavior can be defined both implicitly or explicitly.\n>\n> So the LSP states that when implementations behave differently in a way\n> that affects their consumers, they deserve their own interface.\n>\n> So in general, when it comes to databases, it is the data model that\n> defines the interface. So in case all three databases have the exact data\n> model (i.e. same set of entities), they can use the same contract. But when\n> each database has a different data model (say Mongo conrains Products and\n> ProductDetails, while SQL contains Orders and OrdeItems and Oracle contains\n> Customers), in that case LSP states that the IDataReader should be split\n> into multiple abstractions.\n>\n> —\n> Reply to this email directly or view it on GitHub\n> <https://github.com/simpleinjector/SimpleInjector/issues/196#issuecomment-191001020>\n> .\n>\n"}}