[英]How to use Inheritance Abstract Class?
我需要一些有關 Inheritance class 示例的幫助(摘要)。 我不能使用我的 function ToCSV() 因為我返回了 BananaPart 的列表,而 C# 想要一個 FruitPart 的列表。 怎么可能解決這個問題?
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
FruitFactory fruitFactory = new FruitFactory();
Fruit myFruit = fruitFactory.Create("banana");
myFruit.FruitPart.ForEach(f => Console.WriteLine(f.ToString()));
}
}
public class FruitFactory {
public Fruit Create(string fruitType) {
switch(fruitType) {
case "banana":
return new Banana();
break;
default:
throw new Exception("undefined fruitType");
}
}
}
public abstract class Fruit {
protected string _name;
protected List<FruitPart> _fruitPart;
public Fruit() {
this._name = "A fruit";
}
public string Name { get { return this._name; } }
public List<FruitPart> FruitPart { get { return this._fruitPart; } }
}
public abstract class FruitPart { }
public class Banana : Fruit {
public Banana() : base() {
this._name = "banana";
this._fruitPart = ToCSV();
}
public List<BananaPart> ToCSV(){
return new List<BananaPart> { new BananaPart(5, "10"), new BananaPart(10, "20"), new BananaPart(20, "40") };
}
}
public class BananaPart : FruitPart {
private int _seed;
private string _dimensionPart;
public BananaPart (
int seed,
string dimensionPart
) {
this._seed = seed;
this._dimensionPart = dimensionPart;
}
}
我很高興能更多地了解它! 先感謝您 !
您的代碼未編譯的原因是因為List<T>
不是協變的。 為了編譯您的代碼,您需要使用具有協變類型參數的IEnumerable<T>
更改List<T>
。 所以變化是:
public abstract class Fruit {
protected string _name;
protected IEnumerable<FruitPart> _fruitPart;
public Fruit() {
this._name = "A fruit";
}
public string Name { get { return this._name; } }
public IEnumerable<FruitPart> FruitPart { get { return this._fruitPart; } }
}
您可以在此處了解有關協方差的更多信息: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/
簡而言之,協方差可以讓您根據其他兩種類型的賦值兼容性來推斷兩種類型的賦值兼容性。 由於我們可以將BananaPart
分配給FruitPart
,因此我們可以推斷IEnumerable<BananaPart>
可以分配給IEnumerable<FruitPart>
。
您的 model 有問題。 假設我有一個香蕉,它有一個水果部分的列表。 現在我可以調用myBananana.FruitParts.Add(new ApplePart())
,因為香蕉只由香蕉部分組成,所以這是行不通的。
為避免這種情況,您需要對返回的內容進行更多限制。 您可以使用IEnumerable<Fruitpart>
而不是使用List<FruitPart>
FruitPart> 。 這避免了這個問題,因為您不能向IEnumerable
添加任何內容。
如果您正在學習,我還建議您從接口而不是抽象類開始。 后者有時稱為“實現繼承”,即用於在兩個派生類之間共享代碼。 這有時很有用,但在大多數情況下,最好將此共享代碼放在第三個 class 中,有時稱為“組合優於繼承”。
使用接口,您的水果可能會像這樣:
public interface IFruit
{
string Name { get; }
IEnumerable<IFruitPart> FruitPart { get; }
}
public class Banana : IFruit
{
public Banana() : base() => FruitPart = ToCSV();
public static List<BananaPart> ToCSV() => new List<BananaPart> { new BananaPart(5, "10"), new BananaPart(10, "20"), new BananaPart(20, "40") };
public string Name { get; } = "Banana";
public IEnumerable<IFruitPart> FruitPart { get; }
}
public interface IFruitPart { }
public class BananaPart : IFruitPart
{
public int Seed { get; }
public string DimensionPart { get; }
public BananaPart(int seed, string dimensionPart) => (Seed, DimensionPart) = (seed, dimensionPart);
}
請注意,與抽象的 class 案例相比,您不需要更多的接口變體代碼。
您不能安全地將List<Child>
轉換為List<Parent>
,因為它會讓您將Apple
添加到List<Banana>
。
您可以改為創建List<FuitPart>
。
public List<FruitPart> ToCSV()
{
return new List<FruitPart> {
new BananaPart(5, "10"),
new BananaPart(10, "20"),
new BananaPart(20, "40") };
}
由於List<BananaPart>
不繼承List<FruitPart>
你不能那樣做。
我建議您制作一些包裝類,例如FruitedDetails
和BananaDetails
來繼承它。 這樣,您可以封裝您正在使用的類的具體細節,並且在打包列表時不必處理各種對象轉換。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.