How can I force cast a data to the generics specified in the method constraint?

I have the following data class and VM class:

public interface IData
{
    string Name
    {
        get;
    }
   }

public class DataPartial: IData
{

    public DataPartial()
    {


    }

    public string Name => "Data partial";
}

public class DataFull : IData
{
    public string Name => "Data full";

    public DataFull()
    {

    }
}

public interface IVM
{
    IData Data { get; }
}
public interface IVM_partial: IVM
{
  new  DataPartial Data { get; }
}


public class VM_Partial : IVM_partial
{
    public VM_Partial()
    {
        Data = new DataPartial();

    }
    public DataPartial Data { get; set; }

    IData IVM.Data => Data;
}
public interface IVM_Total:IVM_partial
{
   new DataFull Data { get; }
}



public class VM_Total : IVM_Total
{


    public VM_Total(IVM_partial dataA)
    {
        Data = new DataFull();
        DataA_interface = dataA;
    }

    public IVM_partial DataA_interface { get; }


    public DataFull Data { get; private set; }

    DataPartial IVM_partial.Data => DataA_interface.Data;

    IData IVM.Data => Data;
}

public static class RunVM<T, VM>
    where T: class, IData
    where VM :class, IVM
{
    public static T RunMe(VM hi)
    {
        var vmA = (hi as VM);  //how to force-cast this to the VM type??!!
        return (T)vmA.Data; 
    }
}

class Program
{
    static void Main(string[] args)
    {
        VM_Partial partialData = new VM_Partial();

        var VMClass = new VM_Total(partialData);


        RunVM<DataFull, IVM_Total>.RunMe(VMClass);
        RunVM<DataPartial, IVM_partial>.RunMe(VMClass); //here it throws exception because I can't force cast the IVM to IVM_partial

    }



}

At the method RunVM<DataPartial, IVM_partial>.RunMe(VMClass);, I want it to return me the DataPartial object, which I know it's there in the object VMClass, but I cannot get it done.

I will get an InvalidCastException when I am at the RunMe method, because the parameter hi is always VMClass, and I can never get it to behave like IVM_partial class. In other words, I can't cast hi to a more basic interface IVM_partial.

How to cast hi to a more basic interface IVM_partial? Is it possible at all, and if not, why not?

Jon Skeet
people
quotationmark

It's not the cast that's the problem - it's that you expect the compiler (or runtime) to pick up on the fact that the cast is to a type that declares a new Data property.

This line in RunMe:

return (T)vmA.Data;

... will always use the Data property declared by IVM, because that's the only property the compiler knows about when it's compiling that method. It doesn't matter that you're casting to another interface that contains a new Data property... the cast is about an execution-time check; it doesn't change which Data property the method uses.

It's unclear to me exactly what you're trying to achieve here, but I strongly suspect that you'll need to change tack significantly - maybe by adding another generic type parameter into the mix, maybe by using polymorphism more, or maybe changing the design more radically.

people

See more on this question at Stackoverflow