C# 在mvvmcross中的viewmodels之间传递多态类型

C# 在mvvmcross中的viewmodels之间传递多态类型,c#,android,xamarin,mvvmcross,C#,Android,Xamarin,Mvvmcross,我有两个按钮,它们都显示一个新的viewmodel,但传递给viewmodel的数据不同。传递的数据并非完全不同,因此它们都从同一个基继承。不幸的是,传递给viewmodel的Init()方法的数据似乎在途中丢失了其运行时类型信息?使用调试器(或代码),传递的数据仅被识别为基类,而不是实际构造并传递给ShowViewModel()方法的派生类 我想做的是不可能的吗 public class BasePasser { } public class PasserA : BasePasser {

我有两个按钮,它们都显示一个新的viewmodel,但传递给viewmodel的数据不同。传递的数据并非完全不同,因此它们都从同一个基继承。不幸的是,传递给viewmodel的Init()方法的数据似乎在途中丢失了其运行时类型信息?使用调试器(或代码),传递的数据仅被识别为基类,而不是实际构造并传递给ShowViewModel()方法的派生类

我想做的是不可能的吗

public class BasePasser
{

}

public class PasserA : BasePasser
{

}

public class PasserB : BasePasser
{

}


public class ViewModelOne : MvxViewModel
{
    // ...
    private void DoSwitchViewModelA()
    {
        var tobepassed = new PasserA {
            // ...
            };

        ShowViewModel<ViewModelTwo>(tobepassed);
    }

    private void DoSwitchViewModelB()
    {
        var tobepassed = new PasserB {
            // ...
            };

        ShowViewModel<ViewModelTwo>(tobepassed);
    }
}

public class ViewModelTwo : MvxViewModel
{
    // ...
    public async Task Init(BasePasser passed)
    {
        if(passed is PasserA)
        {
            // ...
        }
        else if(passed is PasserB)
        {
            // ...
        }
        else
        {
            // Always called/hit
            throw new InvalidOperationException("Unknown data passed");
        }
    }
}
公共类BasePasser
{
}
公共类通行证A:基本通行证
{
}
公共类通行证B:基本通行证
{
}
公共类ViewModelOne:MvxViewModel
{
// ...
私有void DoSwitchViewModelA()
{
var tobepassed=新的PasserA{
// ...
};
ShowViewModel(待分离);
}
私有void DoSwitchViewModelB()
{
var TOBEPASS=新通行证B{
// ...
};
ShowViewModel(待分离);
}
}
公共类ViewModel2:MvxViewModel
{
// ...
公共异步任务初始化(已传递BasePasser)
{
如果(通过的是PasserA)
{
// ...
}
否则,如果(通过为B)
{
// ...
}
其他的
{
//总是打电话/打电话
抛出新的InvalidOperationException(“传递了未知数据”);
}
}
}

在MvvmCross中显示ViewModel实际上是一个相当复杂的过程

调用ShowViewModel(param)时,Mvx将把param值序列化到名称/值字典中。此时,param的类型信息丢失

当ViewModel被实例化时,它最终将查找ViewModel上定义的任何Init方法

如果查看cirriary.MvvmCross.ViewModels.MvxViewModelExtensions.CallBundleMethod(),您将看到它首先查找具有IMvxBundle类型的单个参数的方法。然后它寻找一个不是简单类型的参数(比如string、int等)

如果找到此类型,则假定它是已在ShowViewModel()调用中序列化的对象。然后,它尝试根据Init方法中参数的类型(而不是原始类型)反序列化该值

这就是为什么您只看到基类型,因为Mvx没有初始调用的类型信息,并且在反序列化时,只看到Init方法中的基类型

解决方法是将所有属性放在一个类中。只设置您需要的,并创建一个鉴别器属性,指定它是哪种“类型”

var param=newpasser{PasserType=“A”,ParamA=“ValueA”,…等}

您还可以选择使用命名方法参数


参见

中的Init部分,在MvvmCross中显示ViewModel实际上是一个相当复杂的过程

调用ShowViewModel(param)时,Mvx将把param值序列化到名称/值字典中。此时,param的类型信息丢失

当ViewModel被实例化时,它最终将查找ViewModel上定义的任何Init方法

如果查看cirriary.MvvmCross.ViewModels.MvxViewModelExtensions.CallBundleMethod(),您将看到它首先查找具有IMvxBundle类型的单个参数的方法。然后它寻找一个不是简单类型的参数(比如string、int等)

如果找到此类型,则假定它是已在ShowViewModel()调用中序列化的对象。然后,它尝试根据Init方法中参数的类型(而不是原始类型)反序列化该值

这就是为什么您只看到基类型,因为Mvx没有初始调用的类型信息,并且在反序列化时,只看到Init方法中的基类型

解决方法是将所有属性放在一个类中。只设置您需要的,并创建一个鉴别器属性,指定它是哪种“类型”

var param=newpasser{PasserType=“A”,ParamA=“ValueA”,…等}

您还可以选择使用命名方法参数


请参阅

中的Init部分精彩的答案,谢谢您的解释。链接到您所引用的类:可以用Json替换序列化(这是Mvx最初的工作方式)。如果您做到了这一点,并且启用了Json.Net来命名所有类型,那么您应该能够让序列化工作起来。Json序列化的一种方法显示在极好的答案中,感谢您的解释。链接到您所引用的类:可以用Json替换序列化(这是Mvx最初的工作方式)。如果您做到了这一点,并且启用了Json.Net来命名所有类型,那么您应该能够让序列化工作起来。实现Json序列化的一种方法如所示