3

Edit: My question isn't about a using block and how it works. My question is about the difference in the two ways to do it, shown below.

I'm reading the CQRS Journey Guide, and I don't understand this line of code:

using (repo as IDisposable)

What does that mean? Why use it as IDisposable? In a typical using block, one doesn't need to use it as IDisposable:

using (var repo = this.respositoryFactory()) { // ... }

Any idea why the authors wrote it the first way instead of the second way?

This is the method in which that code appears:

private Conference.Web.Public.Models.Conference GetConference(string conferenceCode)
{
    var repo = this.repositoryFactory();
    using (repo as IDisposable)
    {
        var conference = repo.Query<Conference>()
            .First(c => c.Code == conferenceCode);
        var conferenceModel =
        new Conference.Web.Public.Models.Conference
        {
            Code = conference.Code,
            Name = conference.Name,
            Description = conference.Description
        };
        return conferenceModel;
    }
}
David S.
  • 5,965
  • 2
  • 40
  • 77
Bob Horn
  • 33,387
  • 34
  • 113
  • 219
  • Simple, you cant use any old type in a using block, it has to be a type that is IDisposable. – iamkrillin Nov 15 '13 at 21:48
  • 3
    How does `as IDisposable` magically allow the instance to be disposed if its class does not implement `IDisposable`? And if it already implements `IDisposable`, why wouldn't that be enough for the `using` statement? I've never seen it require a cast. – Jeroen Vannevel Nov 15 '13 at 21:50
  • 1
    @iamkrillin You don't have to set something 'as IDisposable' in a using block if it's already disposable. – Bob Horn Nov 15 '13 at 21:51
  • @BobHorn You are incorrect, sir, the simple act of putting an instance of an object into a using block does not make it disposable. http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.110).aspx – iamkrillin Nov 15 '13 at 21:53
  • @iamkrillin: True. That's what `: IDisposable` is for. How does `as IDisposable` fix this? – Jeroen Vannevel Nov 15 '13 at 21:54
  • all the as statement does is a safe cast operation. http://msdn.microsoft.com/en-us/library/vstudio/cscsdfbt.aspx I suspect the author done that to make it explicit – iamkrillin Nov 15 '13 at 21:55
  • You keep explaining general syntax of the language and somehow expect that to explain why a cast is done here. Why is the cast done? – Jeroen Vannevel Nov 15 '13 at 21:56
  • 1
    well the short answer, the cast is not necessary. – iamkrillin Nov 15 '13 at 21:58
  • 2
    Good explanation here: http://stackoverflow.com/questions/4695649/cast-type-to-idisposable-why – sakura-bloom Nov 15 '13 at 22:21

3 Answers3

10

Any idea why the authors wrote it the first way instead of the second way?

This is often due to a misunderstanding of the language feature. The way you wrote it is the idomatic way to write it in C#:

using (var repo = this.respositoryFactory()) 
{

The only real advantage to the author's approach would be if repositoryFactory could, potentially, return a type which doesn't implement IDisposable. By writing the code via using (repo as IDisposable), the same code could handle non-disposable types.

Most of the time, this isn't an issue. However, it would be possible that the factory could optionally return an IDisposable type. As an example, suppose this method was done within a generic class, and repositoryFactory returned an IRepository<T>, it would be possible that type may or may not implement IDiposable, in which case this approach would handle both cases without imposing an IDisposable constraint on the generic type.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Doesn't that assume that `repositoryFactory` returns a type that implements `IDisposable`? What if it returned object, for example? – CodeNaked Nov 15 '13 at 21:55
  • 3
    @CodeNaked `repositoryFactory` would have to return an IDisposable or it wouldn't compile. – Bob Horn Nov 15 '13 at 21:59
  • @BobHorn - Yes, but if it was a type that may or may not implement `IDisposable`, which may be the case with "factories", then you'd be required to cast it to an `IDisposable`. This doesn't seem to apply to this particular case, but you didn't show the type definition of the `repositoryFactory`. – CodeNaked Nov 15 '13 at 22:05
  • @CodeNaked: it throws a compiler error if the return type of the factory does not hold `IDisposable` for certain. It has to return either `IDisposable` or a class/interface that implements it. – Jeroen Vannevel Nov 15 '13 at 22:09
  • @JeroenVannevel - That's not true. I could do `using (var m = this.respositoryFactory() as IDisposable)` then `respositoryFactory` can return any object, whether it implements `IDisposable` or not. If it doesn't, then the user is a no-op. – CodeNaked Nov 15 '13 at 22:11
  • @JeroenVannevel - Sorry, you are correct in that it would be a compiler error if you didn't cast. But the point of the cast is to say, if it implements IDisposable, then dispose it as part of the using. – CodeNaked Nov 15 '13 at 22:12
  • @CodeNaked: I retract my words, you are correct. It works just fine with the casting. That's a neat trick. – Jeroen Vannevel Nov 15 '13 at 22:12
  • 1
    @CodeNaked: If you say `using m=this.repositoryFactory() as IDisposable`, then if the object returned by `repositoryFactory()` doesn't implement `IDisposable`, `m` will be null. In the code as originally written, `repo` would hold a reference to the object that doesn't implement `IDisposable` while the using block would perfectly happily guard `null`. – supercat Nov 15 '13 at 22:15
  • The issue isn't just with generic types. It's entirely possible for a factory method whose declared return type does not implement `IDisposable` to create object instances of types which do implement `IDisposable` and which require cleanup. The non-generic `IEnumerable.GetEnumerator()` is like that. I would regard such factory methods as an *extreme anti-pattern*, but since such things exist, code which uses them must make do as best it can, and the pattern shown in the original code is probably the best that can be done. – supercat Nov 15 '13 at 22:17
  • @CodeNaked: If you declare the variable within the `using` and an object instance doesn't implement `IDisposable`, the fact the variable is null won't only prevent `Dispose` being called on the object (which it should) but *won't allow anything else to be done with the object either*. Making the declaration separate avoids that problem. – supercat Nov 15 '13 at 22:20
  • @supercat Yes, very true - was intended to be an example - will reword to make it more clear that it doesn't require generic types. – Reed Copsey Nov 15 '13 at 22:26
3

Saying using(X as IDisposable) instructs the compiler that X identifies a particular instance of a type which implements IDisposable, then the using block should guard that instance, and otherwise it should guard nothing. Such a usage would be appropriate if the return type of the method this.repositoryFactory() did not implement IDisposable, but the method would sometimes return instances of types which do implement IDisposable and expect it to be called.

Note that any type which will be used as the return type of a factory that may produce IDisposable objects needing cleanup should implement IDisposable, even if only 99.9% of the objects generated would have Dispose methods that do nothing and don't actually have to be called. The non-generic IEnumerator fits that description to a "T", and thus should have implement IDisposable, but since it doesn't the best usage pattern is probably:

IEnumerator enumerator = myEnumerable.GetEnumerator();
using (enumerator as IDisposable)
{
  ...
}

Very similar to what is observed in the code using repositoryFactory() above.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

if somewhere in the using block the code fails, or reach a point of exception. Its guaranteed that repo is beeing disposed.

Difference between the two lines is that there is no difference. cast to IDisposable is not nessecary, it is purely theorethical. possible differences

  • after the using you want to do something with repo.
  • cleaner code
lordkain
  • 3,061
  • 1
  • 13
  • 18
  • 1
    I get that. Wouldn't that be the case for either approach? What's the difference between the two? – Bob Horn Nov 15 '13 at 21:50
  • If the return type of `DepositoryFactory` does not implement `IDisposable`, but that method may sometimes generate instances of types which *do* implement `IDisposable` and would thus require cleanup, the `as IDisposable` will be necessary. – supercat Nov 15 '13 at 22:10