创建一个可以是多种类型的构造函数属性?

您好,我很想知道如何在 C# 中创建可以是多种类型的构造函数属性。

我可以按照下面的方式在 python 中生成我想要的内容。IE 初始化“this_thing”类的对象,该对象可以采用“thing”或“thingy”类的对象。

与我想做的事情等效的Python工作是:

class thing:

    def __init__(self, number):

        self.number = number

    @property

    def number(self):

        return self._number

    @number.setter

    def number(self, value):

        if not isinstance(value, int):

            raise TypeError('"number" must be an int')

        self._number = value


class thingy:

    def __init__(self, text):

        self.text= text

    @property

    def text(self):

        return self._text

    @text.setter

    def text(self, value):

        if not isinstance(value, str):

            raise TypeError('"text" must be a str')

        self._text = value


class this_thing:

    def __init__(self, chosen_thing, name_of_the_thing):

        self.chosen_thing = chosen_thing

        self.name_of_the_thing = name_of_the_thing 

    @property

    def chosen_thing(self):

        return self._chosen_thing

    @chosen_thing.setter

    def chosen_thing(self, value):

        if (not isinstance(value, (thing, thingy))):

            raise TypeError('"chosen_thing" must be a thing or thingy')

        self._chosen_thing = value


    @property

    def name_of_the_thing(self):

        return self._name_of_the_thing

    @name_of_the_thing.setter

    def name_of_the_thing(self, value):

        if not isinstance(value, str):

            raise TypeError('"name_of_the_thing" must be a str')

        self._name_of_the_thing = value


some_thing = thing(10)

another_thing = thingy("10")

new_thing = this_thing(some_thing, "Some Thing")

another_new_thing = this_thing(another_thing, "Another Thing")

在 C# 中,我有独立工作的“Thing”和“Thingy”类。但我想创建一个新类“ThisThing”,它可以采用“Thing”类或“Thingy”类的对象,但我不确定如何启用此操作。

在 C# 中尝试之后,看起来最可行的解决方案是将“ThisThing”类分成两个单独的类。看来 C# 在操作类类型方面不如 Python 灵活。当然,如果您知道如何在 C# 中重现上述 python 代码,请发表评论。知道的话会很方便。


一只萌萌小番薯
浏览 107回答 1
1回答

泛舟湖上清波郎朗

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 propertyConsole.WriteLine(newThing.ChosenThing.Text);// Vice VersaConsole.WriteLine(anotherNewThing.ChosenThing.Number);使用通用接口的更好方法一种更容易接受的面向对象方法是为“可接受的”类型提供一个公共基类或接口,然后使用它来代替。这样您将获得编译时类型安全检查。// Common interfacepublic 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());
打开App,查看更多内容
随时随地看视频慕课网APP