Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何编写指定创建逻辑的接口或抽象类?_C#_Oop_Generics_Interface_Abstract Class - Fatal编程技术网

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

我有一个通用类,它处理可以从字符串反序列化的小部件。泛型类的实例将其中一个小部件的类型作为模板参数,然后从字符串创建这些小部件。我希望使用C#的泛型的协方差特性来编写类似
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()一起工作。
为什么?