{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/csharplang/issues/1475","repository_url":"https://api.github.com/repos/dotnet/csharplang","labels_url":"https://api.github.com/repos/dotnet/csharplang/issues/1475/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/csharplang/issues/1475/comments","events_url":"https://api.github.com/repos/dotnet/csharplang/issues/1475/events","html_url":"https://github.com/dotnet/csharplang/issues/1475","id":316765606,"number":1475,"title":"Proposal/Discussion: Automatic Interfaces","user":{"login":"lemonlion","id":8618373,"avatar_url":"https://avatars2.githubusercontent.com/u/8618373?v=4","gravatar_id":"","url":"https://api.github.com/users/lemonlion","html_url":"https://github.com/lemonlion","followers_url":"https://api.github.com/users/lemonlion/followers","following_url":"https://api.github.com/users/lemonlion/following{/other_user}","gists_url":"https://api.github.com/users/lemonlion/gists{/gist_id}","starred_url":"https://api.github.com/users/lemonlion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lemonlion/subscriptions","organizations_url":"https://api.github.com/users/lemonlion/orgs","repos_url":"https://api.github.com/users/lemonlion/repos","events_url":"https://api.github.com/users/lemonlion/events{/privacy}","received_events_url":"https://api.github.com/users/lemonlion/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":16,"created_at":"2018-04-23T11:10:20Z","updated_at":"2018-04-23T20:29:41Z","closed_at":null,"author_association":"NONE","body":"There's a common pattern where class interfaces end up being created for the sole purpose of mocking in unit testing.  This ends up creating a lot of boilerplate code as no actual alternative implementation is ever intended beyond the mock in the unit tests.  These unit test-only interfaces must then be maintained every time there is a change to the class.\r\n\r\nI propose a solution to this where a \"default\" interface can be defined and generated.\r\n\r\n**_So for example this:_**\r\n\r\n\r\n```\r\npublic class DependencyClass\r\n{\r\n\tpublic void SomeMethod()\r\n        // ...and many other methods/properties etc\r\n}\r\n\r\npublic class ExampleClass\r\n{\r\n\tprivate readonly I<<DependencyClass>> myContructorParameter;\r\n\r\n\tpublic ExampleClass(I<<DependencyClass>> myContructorParameter)\r\n\t{\r\n\t\tmyConstructorParameter = _myContructorParameter;\r\n\t}\r\n}\r\n\r\npublic class UnitTestsForExampleClass\r\n{\r\n\tprivate readonly ExampleClass _serviceUnderTest;\r\n\r\n\tpublic UnitTestsForExampleClass()\r\n\t{\r\n                var _dependency = new Mock.Of<I<<DependencyClass>>>();\r\n\t\t_serviceUnderTest = new ExampleClass(_dependency);\r\n\t}\r\n}\r\n```\r\n\r\n\r\n**_Would be similar to_**\r\n\r\n```\r\n\r\npublic interface IDependencyClass\r\n{\r\n\tvoid SomeMethod()\r\n        // ...and many other methods/properties etc\r\n}\r\n\r\npublic class DependencyClass : IDependencyClass\r\n{\r\n\tpublic void SomeMethod()\r\n        // ...and many other methods/properties etc\r\n}\r\n\r\npublic class ExampleClass\r\n{\r\n\tprivate readonly IDependencyClass myContructorParameter;\r\n\r\n\tpublic ExampleClass(IDependencyClass myContructorParameter)\r\n\t{\r\n\t\tmyConstructorParameter = _myContructorParameter;\r\n\t}\r\n}\r\n\r\npublic class UnitTestsForExampleClass\r\n{\r\n\tprivate readonly ExampleClass _serviceUnderTest;\r\n\r\n\tpublic UnitTestsForExampleClass()\r\n\t{\r\n                var _dependency = new Mock.Of<IDependencyClass>();\r\n\t\t_serviceUnderTest = new ExampleClass(_dependency);\r\n\t}\r\n}\r\n\r\n\r\n```\r\nI used the double bracket syntax (`I<<ClassName>>`) to distinguish it from a generic of a class called 'I', but completely open to syntax suggestions. \r\n\r\nAs far as I see it, this could be implemented in one of two ways: \r\n\r\n1) High level, making it a kind of syntactic sugar. The code would be automatically/invisibly translated at compile time (similarly to the way that extension methods get converted into static classes in c# 7 and below).  The disadvantage of this would be that you would only be able to use this syntax on classes that are created by you in your solution as you can't force an interface onto an external class.  This would however still be an advantage over the current state of autogenerating interfaces using VS/Resharper and then having to maintain them.\r\n\r\n2) Low level.  Make all c# classes implement a default interface of themselves, only accessible via the \"default interface\" syntax (eg `I<<ClassName>>`).  This would allow this syntax to be used on all classes that have been compiled from the correct version of c# upwards. \r\n\r\nPlease note, in my proposal, the interface `I<<DependencyClass>>` would/should be separate to an interface created by the user called `IDependencyClass`. ie there would/should be no namespace conflicts to creating an interface called `IDependencyClass` as well."},"comment":{"url":"https://api.github.com/repos/dotnet/csharplang/issues/comments/383712144","html_url":"https://github.com/dotnet/csharplang/issues/1475#issuecomment-383712144","issue_url":"https://api.github.com/repos/dotnet/csharplang/issues/1475","id":383712144,"user":{"login":"theunrepentantgeek","id":1272094,"avatar_url":"https://avatars2.githubusercontent.com/u/1272094?v=4","gravatar_id":"","url":"https://api.github.com/users/theunrepentantgeek","html_url":"https://github.com/theunrepentantgeek","followers_url":"https://api.github.com/users/theunrepentantgeek/followers","following_url":"https://api.github.com/users/theunrepentantgeek/following{/other_user}","gists_url":"https://api.github.com/users/theunrepentantgeek/gists{/gist_id}","starred_url":"https://api.github.com/users/theunrepentantgeek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/theunrepentantgeek/subscriptions","organizations_url":"https://api.github.com/users/theunrepentantgeek/orgs","repos_url":"https://api.github.com/users/theunrepentantgeek/repos","events_url":"https://api.github.com/users/theunrepentantgeek/events{/privacy}","received_events_url":"https://api.github.com/users/theunrepentantgeek/received_events","type":"User","site_admin":false},"created_at":"2018-04-23T20:29:41Z","updated_at":"2018-04-23T20:29:41Z","author_association":"NONE","body":"There are many ways to create *seams* that allow for pieces of an application to be tested in isolation. Interfaces are one; virtual methods are another; delegates and events are two more.\r\n\r\nFor the (IMHO rare) cases where these are insufficient, there are other ways. [Microsoft Fakes](https://msdn.microsoft.com/en-us/library/hh549175.aspx) is perhaps the best known.\r\n\r\nI recently stumbled across [Pose](https://github.com/tonerdo/pose). Quoting from the project page:\r\n\r\n> Pose allows you to replace any .NET method (including static and non-virtual) with a delegate. It is similar to Microsoft Fakes but unlike it Pose is implemented entirely in managed code (Reflection Emit API). Everything occurs at runtime and in-memory, no unmanaged Profiling APIs and no file system pollution with re-written assemblies.\r\n\r\nI haven't tried it myself, but it would be worth checking out."}}
{"actor":{"display_login":"theunrepentantgeek"}}