将泛型类型转换为基类

时间:2019-03-25 15:38:47

标签: c# generics

public class Base {...}

public class Complex: Base {...}

public class MyOtherClass<T> {...}

以及这两种类型的列表

List<MyOtherClass<Complex>> listOfComplex
List<MyOtherClass<Base>> listOfBase

我想要一个列表

listOfComplex.Union(listOfBase)

但是我无法将一种类型的泛型转换为另一种类型的泛型,即使Complex是从Base派生的 有一个基类列表的可能性吗?

4 个答案:

答案 0 :(得分:3)

尽管Complex源自Base,但MyOtherClass<Complex>MyOtherClass<Base>之间没有没有这种关系。这就是为什么您不能在两个列表中创建一个Union的原因。对于框架这两种通用类型完全不同

现在的解决方案实际上取决于您的班级到底做什么。在Docs中查看协方差和逆方差的主题-这是两种特殊情况,如果类型仅是输入或输出,则可以在两个通用类型之间创建转换。

您还可以在执行“联合”操作之前添加自定义类型转换或将项目手动转换为“基本”类型。

答案 1 :(得分:1)

由于Covariance and Contravariance in Generics的工作方式,尤其是invariance,这意味着您只能使用最初指定的类型;因此不变的泛型类型参数既不是协变也不是协变。

您不能将List<Base>的实例分配给类型为List<Complex>或相反的变量。自定义通用类也是如此。编译器不能使用隐式转换来转换类型。

即使添加通用类型约束。 A<B>A<C>是两种不同的类型,即使C是从B继承而来的,它们之间也没有转换(因为AC不是从{{1}继承而来的) })

答案 2 :(得分:0)

您应该在您的泛型中指定T是基于Type的类:

<?php

$clientName = "";
$squareFeet = 0;
$capRate    = 0;
$utilityBillSavings = 0;
$cashPayments = 0;
$prodVal = 0;

  if(isset($_POST["clientName"]) && isset($_POST['squareFeet']) && isset($_POST['capRate']) && isset($_POST['utilityBillSavings']) && isset($_POST['cashPayments'])) {
    $clientName           = $_POST['clientName']; echo $clientName . "<br>";
    $squareFeet           = $_POST['squareFeet']; echo $squareFeet . "<br>";
    $capRate              = $_POST['capRate']; echo $capRate . "<br>";
    $utilityBillSavings   = $_POST['utilityBillSavings']; echo $utilityBillSavings . "<br>";
    $cashPayments         = $_POST['cashPayments']; echo $cashPayments . "<br>";
    $capRate              = $capRate / 100;
    $propVal              = (($utilityBillSavings/$squareFeet)/$capRate)*$squareFeet;
    echo "Property Value Increase is: " . $propVal . "<br>";
  }

?>
<html><head><body>
  <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>" name="form" id="form">
    <div>Client name</div><div><input type="text" name="clientName" size="20"></div>
    <div>Sq Ft</div><div><input type="number" name="squareFeet" min="0" max="1000000000000"></div>
    <div>Cap Rate</div><div><input type="number" name="capRate"  min="0" max="1000000000000"></div>
    <div>Bill Savings</div><div><input type="number" name="utilityBillSavings"  min="0" max="1000000000000"></div>
    <div>Cash Payment</div><div><input type="number" name="cashPayments"  min="0" max="1000000000000"></div>
    <div><input type="button" name="submit" value="   Calculate Increase In Property Value   "></div>
  </form>

</body></html>


仅当从Base And Union派生的T应该起作用时,T才会被接受

由于@Marie,这里有一些有关泛型的文档:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

答案 3 :(得分:0)

@MartinZikmund解释了为什么它不起作用。解决此类问题的方法是从非泛型基类派生泛型类,或者让它们实现公共接口。

    public class MyOtherClassBase { }
    public class MyOtherClass<T> : MyOtherClassBase { }

然后,您可以显式指定MyOtherClassBase作为Union的通用参数。现在,Union将期望输入IEnumerable<MyOtherClassBase>类型。类型List<MyOtherClass<T>>的列表与IEnumerable<MyOtherClassBase>兼容。

var result = listOfComplex.Union<MyOtherClassBase>(listOfBase);

请注意声明中的out关键字

public interface IEnumerable<out T> : System.Collections.IEnumerable

它使接口协变。另请参阅问题<out T> vs <T> in Generics,尤其是里德·科普西(Reed Copsey)的answer