C# 如何编写指定创建逻辑的接口或抽象类?
我有一个通用类,它处理可以从字符串反序列化的小部件。泛型类的实例将其中一个小部件的类型作为模板参数,然后从字符串创建这些小部件。我希望使用C#的泛型的协方差特性来编写类似C# 如何编写指定创建逻辑的接口或抽象类?,c#,oop,generics,interface,abstract-class,C#,Oop,Generics,Interface,Abstract Class,我有一个通用类,它处理可以从字符串反序列化的小部件。泛型类的实例将其中一个小部件的类型作为模板参数,然后从字符串创建这些小部件。我希望使用C#的泛型的协方差特性来编写类似WidgetUser的代码,以处理可能是WidgetUser或WidgetUser的对象。问题是,要从WidgetUser中的字符串创建小部件,我必须添加new()作为保护。这使得WidgetUser成为无效类型。目前,我有如下代码: interface IWidget { // Makes this widget in
WidgetUser
的代码,以处理可能是WidgetUser
或WidgetUser
的对象。问题是,要从WidgetUser
中的字符串创建小部件,我必须添加new()
作为保护。这使得WidgetUser
成为无效类型。目前,我有如下代码:
interface IWidget
{
// Makes this widget into a copy of the serializedWidget
void Deserialize(string serializedWidget);
}
class WidgetUser<T> where T : IWidget, new()
{
public void MakeAndUse(string serializedWidget)
{
var widget = new T();
widget.Deserialize(serializedWidget);
Use(widget);
}
}
使用此代码,我可以创建一个WidgetUser
,然后编写只处理WidgetUser
的代码。我可以用一个抽象类BaseWidget
而不是IWidget
来编写类似的代码,它可以完成几乎相同的事情。这是功能性的,但我怀疑有一种更直接的方法不会强迫我定义一个虚拟类。如何在不创建虚拟类或额外工厂的情况下将我的意图传达给类型系统。我只想要一个界面,上面写着“你可以从一个字符串中制作一个”
TL;博士:
是否有某种方法可以编写一个接口或抽象类,让我从字符串创建一个实例,但不需要我在
WidgetUser
上使用new()
作为守卫?我将实现WidgetFactory
并调用WidgetFactory.create(serializedWidget)
以避免使用new t()
这里的问题是您的反序列化()
方法应该是静态方法。因此,它不应该是IWidget
本身的成员-它应该是工厂接口的成员,或者应该是从具体工厂方法调用的具体小部件类的静态成员。我将在下面展示后一种方法
(或者,您可以使用Func
委托来指定它,但更常见的是提供完整的factory接口。)
因此,我建议您创建factory界面:
interface IWidgetFactory
{
IWidget Create(string serialisedWidget);
}
然后从IWidget
中删除反序列化()
interface IWidget
{
// .. Whatever
}
class MyWidget: IWidget
{
public static MyWidget Deserialize(string serializedWidget)
{
// .. Whatever you need to deserialise into myDeserializedObject
return myDeserializedObject;
}
// ... Any needed IWidget-implementing methods and properties.
}
然后将静态反序列化()
方法添加到IWidget
的每个具体实现中:
interface IWidget
{
// .. Whatever
}
class MyWidget: IWidget
{
public static MyWidget Deserialize(string serializedWidget)
{
// .. Whatever you need to deserialise into myDeserializedObject
return myDeserializedObject;
}
// ... Any needed IWidget-implementing methods and properties.
}
然后使用具体小部件类中的静态反序列化()
方法为具体小部件类实现工厂:
sealed class MyWidgetFactory : IWidgetFactory
{
public IWidget Create(string serialisedWidget)
{
return MyWidget.Deserialize(serialisedWidget);
}
}
然后将构造函数添加到您的WidgetUser
类中,该类接受IWidgetFactory
,并在MakeAndUse()中使用它:
请注意,在这个场景中,您不再需要WidgetUser
的type参数,因此我将其删除
然后,在创建WidgetUser
时,必须提供工厂:
var widgetUser = new WidgetUser(new MyWidgetFactory());
...
widgetUser.MakeAndUse("MySerializedWidget1");
widgetUser.MakeAndUse("MySerializedWidget2");
通过工厂可以获得更大的灵活性
例如,假设您的序列化方案包含一种从序列化字符串判断它是哪种小部件的方法。为了简单起见,假设它以“[MyWidget]”
开头(如果是MyWidget
),以[“MyOtherWidget”]
开头(如果是MyOtherWidget
)
然后,您可以实现一个工厂,它作为一个“虚拟构造函数”工作,可以在给定序列化字符串的情况下创建任何类型的小部件,如下所示:
sealed class GeneralWidgetFactory: IWidgetFactory
{
public IWidget Create(string serialisedWidget)
{
if (serialisedWidget.StartsWith("[MyWidget]"))
return myWidgetFactory.Create(serialisedWidget);
else if (serialisedWidget.StartsWith("[MyOtherWidget]"))
return myOtherWidgetFactory.Create(serialisedWidget);
else
throw new InvalidOperationException("Don't know how to deserialize a widget from: " + serialisedWidget);
}
readonly MyWidgetFactory myWidgetFactory = new MyWidgetFactory();
readonly MyOtherWidgetFactory myOtherWidgetFactory = new MyOtherWidgetFactory();
}
请注意,这通常不是最好的方法-最好使用依赖项容器(如Autofac)来管理此类内容。,因为IWidget实例不能保证与new()一起工作。
为什么?是因为new()
必须有一个公共的无参数构造函数吗?如果是这样,则使用class
代替。您可能需要以某种方式提供factory对象,或者需要使用new()
约束。为什么你不能简单地扭转你的问题,说小部件类必须有一个无参数构造函数才能与你的小部件用户一起工作?我如何为小部件指定一个接口或抽象基类来保证一个无参数构造函数?目前我不明白你的抽象MakeAndUse
有什么问题,所以我不知道。因为IWidget实例不能保证与new()一起工作。
为什么?