0

this isn't a problem. I just want to understand why it works this way. In the real scenario, the IEnumerable is generated by SimpleInjector thru RegisterCollection if that helps.

This simulator code shows 3 implementations of an interface and the selection of one of those instances based on a parameter. I haven't even coded a call to the method because my question is about the compilation errors.

void Main()
{

}

// Define other methods and classes here
public interface ITransport
{
    void Play();
    bool Pause();
    int Rewind();
    int Ffwd();
    void Stop();
    void Eject();
}

public class PlayerBase : ITransport
{
    public string Name;

    public void Play()
    {
        throw new NotImplementedException();
    }

    public bool Pause()
    {
        throw new NotImplementedException();
    }

    public int Rewind()
    {
        throw new NotImplementedException();
    }

    public int Ffwd()
    {
        throw new NotImplementedException();
    }

    public void Stop()
    {
        throw new NotImplementedException();
    }

    public void Eject()
    {
        throw new NotImplementedException();
    }
}

public class TapePlayer : PlayerBase { }
public class CDPlayer : PlayerBase {}
public class EightTrackPlayer : PlayerBase{}
public interface IDependencyRegistry { T Get<T>();}
public class DependencyRegistry<T> : List<T>, IDependencyRegistry
{
    public T1 Get<T1>()
    {
        if (typeof(T).IsInterface && !typeof(T1).GetInterfaces().Contains(typeof(T))) return default(T1);
        return (T1) (object) this.SingleOrDefault(thing => thing.GetType() ==typeof(T1));
    }
}
public class PlayBase
{
    public DependencyRegistry<ITransport> TransportRegistry
    public PlayBase(IEnumerable<ITransport> transports)
    {
        TransportRegistry = new UserQuery.DependencyRegistry<UserQuery.ITransport>();
        TransportRegistry.AddRange(transports);
    }

    public void Play(int playerId)
    {
        var player1 = playerId == 1 ? (ITransport)TransportRegistry.Get<TapePlayer>() : playerId == 2 ? TransportRegistry.Get<CDPlayer>() : null;
    }
}

If you paste this into LinqPad5, it'll compile without error but remove the cast to ITransport and the complaint is that it can't figure out that both concretions stem from the same base and therefore the var (to my ignorant mind) should be assigned as PlayerBase or ITransport.

I'm also confused that only 1 cast is need to satisfy the compiler. If it can figure out the other concretion should also be cast to ITransport, then why can it not deduce either ITransport or PlayerBase from the hierarchy?

stardotstar
  • 318
  • 2
  • 18
  • Sometimes these why questions are hard to answer, and the reason may have been a design choice, or be nested in subtle implementation details or other use cases which aren't quite obvious . The regular SO personality that is qualified to answer the whys, answered the duplicate give,so that is probably the best answer you will get – TheGeneral Jun 09 '18 at 23:10
  • Thanks. Yes, this is a duplicate. Apologies. I also understand from the accepted answer why using ITransport instead of var didn't work and why having cast as ITransport in one place provides the compiler with a best type and the type is therefore inferrable from the other instance. – stardotstar Jun 09 '18 at 23:30

0 Answers0