1 回答

TA貢獻1818條經驗 獲得超3個贊
dynamic
理論上,您可以使用或弱類型(如 )在 C# 中復制動態類型系統object
。
但是,正如您在 Python 中所做的那樣,您將需要在運行時不斷進行類型一致性檢查
這是原始 Python 代碼的轉換dynamic
(不要這樣做)
public class Thing
{
? ? public Thing(int number) { Number = number; }
? ? public int Number { get; }
}
public class Thingy
{
? ? public Thingy(string text) { Text = text; }
? ? public string Text { get; }
}
public class ThisThing
{
? ? public ThisThing(dynamic chosenThing, string nameOfTheThing)
? ? {
? ? ? ? ChosenThing = chosenThing;
? ? ? ? NameOfTheThing = nameOfTheThing;
? ? }
? ? // Cache the accepted types
? ? private static readonly ICollection<Type> AcceptedTypes = new HashSet<Type> { typeof(Thing), typeof(Thingy) };
? ? private dynamic _chosenThing;
? ? public dynamic ChosenThing
? ? {
? ? ? ? get => _chosenThing;
? ? ? ? private set
? ? ? ? {
? ? ? ? ? ? if (!AcceptedTypes.Contains(value.GetType()))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? throw new ArgumentException($"ChosenThing must be {string.Join(" or ", AcceptedTypes.Select(t => t.Name))}");
? ? ? ? ? ? }
? ? ? ? ? ? _chosenThing = value;
? ? ? ? }
? ? }
? ? public string NameOfTheThing { get; }
}
根據您的測試用例,可以執行以下操作:
var someThing = new Thing(10);
var anotherThing = new Thingy("10");
var newThing = new ThisThing(someThing, "Some Thing");
var anotherNewThing = new ThisThing(anotherThing, "Some Thing");
Console.WriteLine(newThing.ChosenThing.Number);
Console.WriteLine(anotherNewThing.ChosenThing.Text);
弱類型的問題是錯誤只能在運行時被檢測到。下面的代碼都會通過編譯器(因為ChosenThing是dynamic),但會在運行時崩潰。
var invalidThing = new ThisThing("Invalid for string types", "Invalid");
// newThing has a Number, not a Text property
Console.WriteLine(newThing.ChosenThing.Text);
// Vice Versa
Console.WriteLine(anotherNewThing.ChosenThing.Number);
使用通用接口的更好方法
一種更容易接受的面向對象方法是為“可接受的”類型提供一個公共基類或接口,然后使用它來代替。這樣您將獲得編譯時類型安全檢查。
// Common interface
public interface IThing { }
public class Thing : IThing
{
? ? public Thing(int number) { Number = number; }
? ? public int Number { get; }
}
public class Thingy : IThing
{
? ? public Thingy(string text) { Text = text; }
? ? public string Text { get; }
}
由于通用接口,IThing現在可以用于約束傳遞給的允許類型ThisThing(即必須符合約定IThing),并且這些類型約束在編譯時強制執行:
public class ThisThing
{
? ? public ThisThing(IThing chosenThing, string nameOfTheThing)
? ? {
? ? ? ? ChosenThing = chosenThing;
? ? ? ? NameOfTheThing = nameOfTheThing;
? ? }
? ? public IThing ChosenThing { get; }
? ? public string NameOfTheThing { get; }
}
Thing您現在可以公開合約之間以及Thingy通過合約的任何常見功能IThing。
就目前而言,該接口沒有通用性,因此您需要將 向下轉換IThing為子類之一,這再次違反了SOLID Liskov Substitution Principle:
Console.WriteLine(((Thing)newThing.ChosenThing).Number);
Console.WriteLine(((Thingy)anotherNewThing.ChosenThing).Text);
所以你真正想要的是抽象共性,例如
public interface IThing?
{?
? ? ?int CalculateValue();
}
現在,兩者Thing都Thingy將被迫提供此抽象的實現,然后接口的使用者現在可以安全地使用該接口,而無需對具體實例的實際類型進行任何進一步的假設:
Console.WriteLine(anyIThing.CalculateValue());
- 1 回答
- 0 關注
- 135 瀏覽
添加回答
舉報