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

C# 使用静态工厂的替代方法(因为不能有抽象静态方法),c#,inheritance,C#,Inheritance,我正在尝试构建一个功能包解析器。我有一个基类数据报,现在我天真地想象我会这样定义它: (编辑时请注意,该类不是抽象的!) 然后对于特定的数据报,例如以太网和Tcp: public class EthernetDatagram : Datagram, IPayloadDatagram { public override static Datagram CreateFromDatagram(Datagram datagram) { return new Etherne

我正在尝试构建一个功能包解析器。我有一个基类
数据报
,现在我天真地想象我会这样定义它:

(编辑时请注意,该类不是抽象的!)

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

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; }
}
这个(不可能的)抽象静态方法的原因是我想要一个扩展方法,它允许我将所有这些数据包“链接”在一起:

public static class DatagramExtensions
{
    public static T As<T>(this IPayloadDatagram datagram) where T : Datagram
    {
        return (T)T.CreateFromDatagram(datagram.Payload);
    }
}
所有这些都是可扩展的

由于我不能继承抽象类,所以这将不起作用,除了实例化这样的泛型类,还有什么好的替代方法呢

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

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

有没有更好的替代方案,在架构上,或者通过某种形式的接口/继承来解决这个问题

(如果有人想看到我正在使用的完整源代码,我会尝试将这些扩展添加到数据包解释库中,作为其中的一部分,并尽可能少地进行修改)

。。。但是我没有办法强制执行,因为有一个特定的 获取有效负载的构造函数

您可以通过在基本抽象类中声明适当的构造函数来实现它

我还建议对代码进行一些修改。由于所有派生类都应该具有相同的
有效负载
属性,所以在base
数据报
类中声明它。还考虑声明<代码>数据报< /代码>类作为实现代码> IPayLoad DATAGRAM < /COD>接口。不必将每个派生类标记为实现此接口

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

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);
    }
}
公共接口IPayloadDatagram
{
数据报有效负载{get;}
}
公共抽象类数据报:IPayloadDatagram
{
公共数据报有效负载{get;}
受保护数据报(数据报数据报)
{
有效载荷=数据报;
}
}
公共类EthernetDatagram:数据报
{
公共以太网数据报(数据报数据报):基本(数据报)
{
}
}
公共静态类DatagramExtensions
{
公共静态T As(此IPayloadDatagram数据报),其中T:数据报
{
return(T)Activator.CreateInstance(typeof(T),datagram.Payload);
}
}

我建议另一种解决方案。我会申请

使用新解决方案更新:

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>();
    }
}
公共类数据报
{
公共字节[]数据{get;set;}
}
公共接口IPayload
{
数据报有效负载{get;}
}    
公共接口IConvertible
{
IPayload转换(IPayload加载);
}
公共类EthernetDatagram:IPayload,IConvertible
{
公共数据报有效载荷
{
得到
{
返回null;
}
}
公共IPayload转换(IPayload加载)
{
返回新的EthernetDatagram();
}
}
公共类TcpDatagram:IConvertible,IPayload
{
公共数据报有效载荷
{
得到
{
返回null;
}
}
公共IPayload转换(IPayload加载)
{
返回null;
}
}
公共静态类扩展
{
公共静态IPayload As(此IPayload加载),其中T:class,IConvertible,new()
{
IConvertible conv=new T();
返回conv.Convert(加载);
}
}
班级计划
{
静态void Main(字符串[]参数)
{
IPayload=新的TcpDatagram();
var result=load.As();
}
}
有了这个解决方案,你就走了另一条路。您离开了硬反射的路径,通过传递要“转换”到的具体类型并拥有完全控制权,将其移动到不同的抽象层。对于新的数据报,您所要做的就是实现这两个接口,只要您希望在它们之间进行转换。 这更适合你的问题吗

更新评论:

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,仅此而已。

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

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

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);
    }
}
公共接口IPayloadDatagram
{
数据报有效负载{get;}
}
公共抽象类数据报
{
公共静态数据报CreateFromDatagram(数据报数据报)
{
var action=datagram.GetConverter();
返回动作(数据报);
}
受保护的抽象Func GetConverter();
}
公共类EthernetDatagram:数据报,IpayloAddDatagram
{
受保护的覆盖函数GetConverter()
{
返回x=>newethernetdatagram();
}
公共数据报有效负载{get;set;}
}
公共类TcpDatagram:数据报、IPayloadDatagram
{
受保护的覆盖函数GetConverter()
{
返回x=>newtcpdatagram();
}
公共数据报有效负载{get;set;}
}
公共静态类DatagramExtensions
{
公共静态T As(此IPayloadDatagram数据报),其中T:数据报
{
返回(T)Datagram.CreateFromDatagram(Datagram.Payload);
}
}

这并不强制构造函数,
公共EthernetDatagram():base(新数据报()
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);
    }
}