我有一个 ASP.NET Razor Pages 项目,其部分 View 使用元组类型作为其模型。元组元素之一使用接口(interface)作为其类型。当使用接口(interface)类型的对象调用分部 View 时,它可以工作。但是当使用实现该接口(interface)的类调用它时,它会抛出异常。
我创建了一个 simplified repo重现此错误。
该项目定义了一个带有类实现的接口(interface):
public interface ISampleInterface
{
int Value { get; }
}
public class ImplementationClass : ISampleInterface
{
public int Value => 5;
}
在页面中,我可以创建类型为接口(interface)或实现接口(interface)的类的对象:
public class IndexModel : PageModel
{
// type is the interface
public ISampleInterface InterfaceInstance { get; } = new ImplementationClass();
// type is an implementation of the interface
public ImplementationClass ClassInstance { get; } = new ImplementationClass();
public void OnGet() { }
}
然后有一个部分 View ,它使用包含接口(interface)的元组作为其模型:
@model (ISampleInterface Sample, int Number)
<p>Sample value: @Model.Sample.Value </p>
<p>Unrelated number: @Model.Number </p>
但是引用分部 View 时,可以使用接口(interface)类型的对象,而类类型的对象会抛出异常:
<!-- This works: -->
<partial name="_SampleTuplePartial" model="(Model.InterfaceInstance, 1)" />
<!-- This throws an exception: -->
<partial name="_SampleTuplePartial" model="(Model.ClassInstance, 1)" />
第一个部分标记按预期呈现,但第二个部分标记抛出此异常:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.ValueTuple<code>2[ImplementationClass,System.Int32]', but this ViewDataDictionary instance requires a model item of type 'System.ValueTuple</code>2[ISampleInterface,System.Int32]'.
两个对象都实现了该接口(interface),那么为什么第二个对象会抛出异常?
只有当模型是元组时才会发生这种情况。仅以接口(interface)作为模型的部分 View 可以与任一类型的对象一起使用:
@model ISampleInterface
<p>Sample value: @Model.Value</p>
<partial name="_SampleInterfacePartial" model="Model.InterfaceInstance" />
<partial name="_SampleInterfacePartial" model="Model.ClassInstance" />
最佳答案
TL;DR:因为ValueTuple
不是协变的。
Covariance enables you to use a more derived type than that specified by the generic parameter
该问题与泛型类型参数有关,而不是分部 View 本身。
例如,给出以下代码:
public static void Main(string[] args)
{
var strings = new List<string>();
// this is fine because IEnumerable is covariant
DoSomething(strings);
// compile error: cannot convert from 'System.Collections.Generic.List<string>' to 'System.Collections.Generic.List<object>'
DoAnotherThing(strings);
}
static void DoSomething(IEnumerable<object> objects)
{
}
static void DoAnotherThing(List<object> objects)
{
}
IEnumerable
泛型类型是协变的,它被声明为 IEnumerable<out T>
。这意味着您可以转换 IEnumerable<string>
至IEnumerable<object>
因为string
源自object
。但你不能施放List<string>
至List<object>
因为List<T>
不是协变的(无论如何都不可能)
ValueTuple
也不是协变的,所以你不能强制转换 ValueTuple<ImplementationClass, int>
至ValueTuple<ISampleInterface, int>
甚至艰难ImplementationClass
实现ISampleInterface
关于c# - 为什么元组中的接口(interface)不能用作 ASP.NET Razor 部分 View 中的模型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72232605/