首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >替代使用静态工厂(因为不能使用抽象的静态方法)

替代使用静态工厂(因为不能使用抽象的静态方法)
EN

Stack Overflow用户
提问于 2017-11-14 09:57:14
回答 3查看 192关注 0票数 3

我正在尝试构建一个功能包解析器。我有一个基类Datagram,现在我天真地以为我会像这样定义它:

(编辑注意事项,这个类不是抽象的!)

代码语言:javascript
复制
public class Datagram
{
    public abstract static Datagram CreateFromDatagram(Datagram datagram);
}

然后,对于特定的数据报,例如以太网和Tcp:

代码语言:javascript
复制
public class EthernetDatagram : Datagram, IPayloadDatagram
{
    public override static Datagram CreateFromDatagram(Datagram datagram)
    {
        return new EthernetDatagram();
    }

    public Datagram Payload { get; }
}

public class TcpDatagram : Datagram, IPayloadDatagram
{
    public overrides static Datagram CreateFromDatagram(Datagram datagram)
    {
        return new TcpDatagram();
    }

    public Datagram Payload { get; }
}

这种(不可能的)抽象静态方法的原因是,我希望有一个扩展方法,允许我将所有这些数据包“链接”在一起:

代码语言:javascript
复制
public static class DatagramExtensions
{
    public static T As<T>(this IPayloadDatagram datagram) where T : Datagram
    {
        return (T)T.CreateFromDatagram(datagram.Payload);
    }
}

因此,要拥有一个全新的数据报类型ANewDatagram,我所需要做的就是让它定义它的工厂方法CreateFromDatagram,然后我将能够愉快地使用我的函数扩展:

代码语言:javascript
复制
SomeDatagram.As<EthernetDatagram>().As<TcpDatagram>().As<ANewDatagram>()... 

这一切都是可扩展的。

考虑到由于我无法继承抽象类,这是行不通的,那么除了实例化这样的泛型类之外,还有什么好的替代方法呢?

我可以使用反射,但这是隐藏它对用户。当我尝试创建ANewDatagram时,我必须记住,我稍后要反映一个CreateFromDatagram方法。

我目前正在使用反射来获取构造函数--但是我没有办法强制使用一个特定的构造函数来获取有效负载。如果有人创建了一个新的Datagram,不能保证他们添加了正确的构造函数,我必须在注释中告诉他们这一点,这很可能会被忽略,而失败的点是在最近的可能点上的运行时。

是否有更好的选择,体系结构,或某种形式的接口/继承,可以绕过这个问题?

(如果有人想看到我正在使用的完整源代码,我会尝试将这些扩展添加到包解释库中,作为https://github.com/PcapDotNet/Pcap.Net的一部分,尽可能少的修改)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-11-14 12:11:20

我会提出一个不同的解决方案。我会申请Depdency反演原理

使用新解决方案更新

代码语言:javascript
复制
public class Datagram
{
    public byte[] Data { get; set; }
}


public interface IPayload
{
    Datagram Payload { get; }

}    

public interface IConvertible
{
    IPayload Convert(IPayload load);
}

public class EthernetDatagram : IPayload , IConvertible
{
    public Datagram Payload
    {
        get
        {
            return null;
        }
    }


    public IPayload Convert(IPayload load)
    {
        return new EthernetDatagram();
    }
}

public class TcpDatagram : IConvertible, IPayload
{
    public Datagram Payload
    {
        get
        {
            return null;
        }
    }

    public IPayload Convert(IPayload load)
    {
        return null;
    }
}

public static  class Extension
{
    public static IPayload As<T>(this IPayload load) where T : class, IConvertible, new()
    {
        IConvertible conv = new T();
        return conv.Convert(load);
    }
}

class Program
{
    static void Main(string[] args)
    {
        IPayload load = new TcpDatagram();

        var result = load.As<EthernetDatagram>();
    }
}

有了这个解决方案,你就走了相反的路。通过传递要“转换”到并拥有完全控制的具体类型,您可以离开硬反射的路径,并将其移动到不同的抽象层。对于新的数据报,您所要做的就是实现这两个接口,只要您希望在它们之间进行转换。这个更适合你的问题吗?

更新到注释:

新的解决办法将克服前一种解决办法的缺点。不通过泛型参数反映和说明“转换”类型。您可以连锁调用'As‘在一起,以达到您想要的准确。您现在唯一需要提供的是接口实现,默认的ctor,也就是它。

票数 3
EN

Stack Overflow用户

发布于 2017-11-14 10:11:06

..。但是,我没有办法强制执行,因为有一个特定的构造函数可以接受有效负载。

您可以通过在基类抽象类中声明适当的构造函数来强制执行它。

我还建议对您的代码进行一些修改。由于所有派生类都应该具有相同的Payload属性,所以请在基类Datagram类中声明它。还可以考虑将Datagram类声明为实现IPayloadDatagram接口。这样就没有必要将每个派生类标记为实现此接口。

下面是示例代码,希望它能满足您的需要:

代码语言:javascript
复制
public interface IPayloadDatagram
{
    Datagram Payload { get; }
}

public abstract class Datagram : IPayloadDatagram
{
    public Datagram Payload { get; }

    protected Datagram(Datagram datagram)
    {
        Payload = datagram;
    }
}

public class EthernetDatagram : Datagram
{
    public EthernetDatagram(Datagram datagram) : base(datagram)
    {
    }
}

public static class DatagramExtensions
{
    public static T As<T>(this IPayloadDatagram datagram) where T : Datagram
    {
        return (T)Activator.CreateInstance(typeof(T), datagram.Payload);
    }
}
票数 3
EN

Stack Overflow用户

发布于 2017-11-14 15:41:02

如果您有一个静态方法,但是该方法引用了一个实现定义的操作,那该怎么办?

这增加了编译时间检查,因此用户至少应该知道转换。

代码语言:javascript
复制
public interface IPayloadDatagram
{
    Datagram Payload { get; }
}

public abstract class Datagram
{
    public static Datagram CreateFromDatagram(Datagram datagram)
    {
        var action = datagram.GetConverter();
        return action(datagram);
    }

    protected abstract Func<Datagram, Datagram> GetConverter();
}

public class EthernetDatagram : Datagram, IPayloadDatagram
{
    protected override Func<Datagram, Datagram> GetConverter()
    {
        return x => new EthernetDatagram();
    }

    public Datagram Payload { get; set; }
}

public class TcpDatagram : Datagram, IPayloadDatagram
{
    protected override Func<Datagram, Datagram> GetConverter()
    {
        return x => new TcpDatagram();
    }

    public Datagram Payload { get; set; }
}

public static class DatagramExtensions
{
    public static T As<T>(this IPayloadDatagram datagram) where T : Datagram
    {
        return (T)Datagram.CreateFromDatagram(datagram.Payload);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47282640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档