C# 是否创建可以是多种类型的构造函数属性?
嗨,我很想知道如何在C#中创建一个可以是多种类型的构造函数属性 我已经查看了堆栈溢出链接: ……但它们似乎与我的调查不符 我可以用python生成我想要的内容,如下所示。 IE初始化“this_thing”类的对象,该对象可以接受“thing”或“thingy”类的对象 与我想做的工作类似的Python是:C# 是否创建可以是多种类型的构造函数属性?,c#,oop,constructor,C#,Oop,Constructor,嗨,我很想知道如何在C#中创建一个可以是多种类型的构造函数属性 我已经查看了堆栈溢出链接: ……但它们似乎与我的调查不符 我可以用python生成我想要的内容,如下所示。 IE初始化“this_thing”类的对象,该对象可以接受“thing”或“thingy”类的对象 与我想做的工作类似的Python是: class thing: def __init__(self, number): self.number = number @property d
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”的对象,但我不确定如何启用此操作。IE声明/启用对象属性为多种类型
namespace TheManyThings
{
class ThisThing
{
public Thing | Thingy NewThing { get; set; }
public string NameOfTheThing { get; set; }
public ThisThing(Thing | Thingy newThing, string nameOfTheThing)
{
NewThing = newThing;
NameOfTheThing = nameOfTheThing
}
}
}
在使用C#之后,看起来最可行的解决方案是将类“ThisThing”分为两个单独的类。在操纵类类型方面,C#似乎不如Python灵活。当然,如果您知道如何用C#重现上述python代码,请发表评论。知道这一点很方便
namespace TheManyThings
{
class ThisThing0
{
public Thing NewThing { get; set; }
public string NameOfTheThing { get; set; }
public ThisThing0(Thing newThing, string nameOfTheThing)
{
NewThing = newThing;
NameOfTheThing = nameOfTheThing
}
}
class ThisThing1
{
public Thingy NewThingy { get; set; }
public string NameOfTheThing { get; set; }
public ThisThing1(Thingy newThingy, string nameOfTheThing)
{
NewThingy = newThingy;
NameOfTheThing = nameOfTheThing
}
}
}
理论上,您可以使用
dynamic
,或者像object
这样的弱类型,在C#中复制一个动态类型的系统
但是,正如您在Python中所做的那样,您将需要在运行时不断地进行类型一致性检查
因此,您将失去像C#这样的静态类型语言的大部分好处,并且您也将受到社区的很多嘲笑
这里是使用动态
对原始Python代码的转换(不要这样做)
弱类型的问题是,只有在运行时才会发现错误。
以下内容都将通过编译器(因为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);
使用通用接口的更好方法
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; }
}
一种更为可接受的OO方法是为“可接受”类型提供一个公共基类或接口,然后改用它。这样,您将得到编译时类型安全检查
// 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; }
}
现在,您可以通过IThing
合同公开Thing
和Thingy
之间的任何通用功能
目前,该接口没有通用性,因此您需要将i字符串
向下转换到其中一个子类,这同样违反了:
所以你真正想要的是抽象出共性,例如
public interface IThing
{
int CalculateValue();
}
Thing
和Thingy
现在都将被迫为这个抽象提供一个实现,然后接口的使用者现在将能够安全地使用接口,而无需对具体实例的实际类型作任何进一步的假设:
Console.WriteLine(anyIThing.CalculateValue());
声明
Thing
和Thingy
以继承一些基类。属性的类型应该是这个类。您应该阅读C#中OOP的基本原理。这是一个可以通过使用两个“东西”都从中继承的基类或接口来解决的问题。@SmokeScreen 899如果这两种类型没有共同的基类,最好是添加两个具有不同参数的独立构造函数。一个用于事物
,一个用于事物
。您也可以使用泛型(ThisThing
),具体取决于您的更高级别需求。@mjwills感谢您的建议。是否有任何方法可以实现您的建议,如您所说,使用两个独立的构造函数,而不需要复制所有的类方法(由于新的参数)?感谢您的非凡响应,以及您为解释“等效”和“最佳实践”之间的差异所做的努力。我已经成功地实现了基于公共接口方法的C#等效代码。非常感谢!我唯一想和大家分享的是(这可能取决于其他因素),我必须在公共接口声明中包含的抽象方法前面删除“public”。但除此之外,它还发挥了作用。再次感谢您的辛勤工作。Oops-我的错,是的,接口方法/属性/事件不能有范围限定符。我已经解除了公众的职务。
public interface IThing
{
int CalculateValue();
}
Console.WriteLine(anyIThing.CalculateValue());