为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
一只萌萌小番薯 2023-07-22 17:03:51
您好,我很想知道如何在 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 = valueclass 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 = valueclass 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 = valuesome_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 代码,请发表评论。知道的话会很方便。
查看完整描述

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());


查看完整回答
反对 回复 2023-07-22
  • 1 回答
  • 0 关注
  • 106 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信