c# - ViewModelBuilder generics casting issue -


this question has answer here:

wracking brain around no avail, wonder if can of help?

getting frustrating casting issue im sure have quick answer, happening due limited understanding of generic type inference or something.

thanks in advance!

scenario number of "step" viewmodels wizard site. i'm creating builder classes each, , using factory grab specific builder step gets posted me, collection of istepviewmodel's.

public interface istepviewmodelbuilderfactory {     istepmodelbuilder<t> create<t>(t stepviewmodel) t : istepviewmodel;     void release<t>(istepmodelbuilder<t> stepviewmodelbuilder) t : istepviewmodel; }  public interface istepviewmodel { }  public interface istepmodelbuilder<tstepviewmodel> : imodelbuilder<tstepviewmodel> tstepviewmodel : istepviewmodel { }  public class specificviewmodelbuilder : istepmodelbuilder<specificstepviewmodel> { }  public class specificstepviewmodel: stepviewmodel { }  public abstract class stepviewmodel : istepviewmodel { } 

the failing test!

[test] public void testresolution() {     var factory = this.container.resolve<istepviewmodelbuilderfactory>();      istepviewmodel viewmodel = new specificstepviewmodel();      var builder = factory.create(viewmodel); // here      assert.that(builder, is.not.null); } 

the problem!

unable cast object of type 'company.namespace.specificviewmodelbuilder ' type 'company.namespace.builders.istepmodelbuilder`1[company.namespace.istepviewmodel]'.

factory impl follows using castle.windsor

public class stepviewmodelselector : defaulttypedfactorycomponentselector {             protected override type getcomponenttype(system.reflection.methodinfo method, object[] arguments)     {         var arg = arguments[0].gettype();         var spectype = typeof(imodelbuilder<>).makegenerictype(arg);         return spectype;     } } 

registration of this:

container.addfacility<typedfactoryfacility>();       ....      container         .register(             classes                 .fromassemblycontaining<stepviewmodelselector>()                 .basedon<stepviewmodelselector>());      container         .register(             component                 .for<istepviewmodelbuilderfactory>()                 .asfactory(c => c.selectedwith<stepviewmodelselector>())); 

stacktrace:

system.invalidcastexception unhandled user code
hresult=-2147467262 message=unable cast object of type 'company.namespace.specificviewmodelbuilder' type 'company.namespace.istepmodelbuilder`1[company.namespace.istepviewmodel]'. source=dynamicproxygenassembly2 stacktrace: @ castle.proxies.istepviewmodelbuilderfactoryproxy.create[t](t stepviewmodel) @ tests.infrastructure.viewmodelbuilderfactorytests.testresolution() in c:\project\infrastructure\viewmodelbuilderfactorytests.cs:line 61
innerexception:

edit: imodelbuilder<t> interface

public interface imodelbuilder<tviewmodel> {     tviewmodel build();     tviewmodel rebuild(tviewmodel model); } 

there 1 interface not showing here, imodelbuilder<t> interface, it's key interface solving problem.

i'm assuming it's defined this

public interface imodelbuilder<t> { } 

if use generic covariance, available since .net 4, you'll able solve problem defining interface this:

public interface imodelbuilder<out t> { } 

the out modifier makes interface covariant, allow cast istepmodelbuilder<specificstepviewmodel> istepmodelbuilder<istepviewmodel>. should note puts constraint on interface won't allow define methods t parameter, return value.

you can read more covariance , contravariance here.

edit

as mentioned in comment, interface looks this:

public interface imodelbuilder<t> {     t create(t myviewmodel); } 

if instead of passing t parameter create, it's ok pass istepviewmodel or other t instead, should solve problem:

public interface imodelbuilder<out t> {     t create(istepviewmodel myviewmodel); } 

if not, attempted cast shouldn't allowed.


Comments