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 关注
- 106 浏览
添加回答
举报