c# – 使用partial从自动生成的linq-sql对象中抽象方法

背景:您好我正在尝试构建像州引擎一样的
Windows工作流程.我有一个基本的引擎设置与动作和触发器 – 动作做自定义代码,触发器是外部事件,允许状态引擎从一个状态移动到另一个状态. Trigger持有许多Actions,当Trigger的bool isMet()条件为真时触发.

我遇到的编码问题是我需要抽象Trigger类的isMet()方法.这样做的原因是我有很多子Trigger类,例如isPaperworkCompletedTrigger继承自基类Trigger类,它们每个都包含自己的自定义isMet()代码.我实现这一点的唯一复杂因素是整个引擎,例如: Trigger和Action需要存储在数据库中.我首先在SQL中构建引擎表,然后使用LINQ-to-SQL构建我的Action和Trigger对象. LINQ-to-SQL允许你通过使用我用来向我的Trigger类添加一个isMet()方法的partial类方法来扩展自动生成的类对象,我不能使这个isMet()方法抽象,因为auto-生成的触发器类不是抽象的(出于显而易见的原因).

我通过继承子类中的基本触发器类来尝试’软覆盖’isMet()方法,例如isPaperworkCompletedTrigger并创建一个名为isMet()的方法,intellisense抱怨这一点并告诉我停止intellisense抱怨在方法上使用’new’关键字.正如所料,这种“软覆盖”方法不起作用.

当Triggerobjects被拉出数据库并且自然地调用isMet()方法时,基本方法isMet()方法被调用(来自Trigger类,而不是子类),这是有意义的,因为数据库没有办法知道触发器的哪个子节点调用isMet()方法.

对此明显的解决方案是在Triggers表中粘贴TriggerName字段,并在该字段上执行一个好的旧开关案例,根据名称字段调用Trigger的相应子类的isMet()方法.这是我想要避免的.

我希望这个项目能够让用户“插入”Trigger和Action.我计划实现这一目标的方法是允许用户将自己的自定义Trigger派生类作为DLL放入指定的文件夹,并让工作流引擎能够在不重新部署或重建的情况下使用它们(这排除了大量的交换机)关于静态字符串的case语句).

这个问题的核心是如何读取所有触发器模块(一个DLL是一个触发器模块),并在此对象上调用isMet()方法(无需访问其类代码).

我怀疑解决这个问题的攻击点在于使Trigger类成为isMet()方法的抽象或者将某种转换器类从数据库Trigger类转换为’offline’Trigger类并使该离线类成为抽象类(我可以覆盖).

任何人都可以帮助解决这个问题.

非常抱歉我的小说延长问题,但问题需要相当多的信息才能让任何人理解这个问题.

谢谢

最佳答案 而不是在基本Trigger类抽象上创建isMet()方法,而是使其为
virtual,默认值可能为false.然后,您可以使用override关键字在派生类中使用
override方法.

您的第二个问题涉及序列化和反序列化数据库的触发器.反序列化时,您希望确保获得派生的触发器类型,而不是基础.我不知道你是如何选择将对象序列化为数据库的,但是你需要一种方法来存储类型.让我们以DataContractSerializer为例.它接受一个Type作为它的第一个参数.如果在序列化触发器时将typeof(DerivedTrigger)存储到数据库中的另一个字段,则可以反序列化Type并使用它将Trigger反序列化为正确的派生类型.然后调用isMet()方法应该调用派生的overriden值.以下是使用静态变量代替数据库的简短示例:

[DataContract]
partial class Trigger
{
    public virtual bool isMet()
    {
        return false;
    }
}

[DataContract]
class DerivedTrigger : Trigger
{
    public object DataElement1 { get; set; }
    //and other properties to serialize.

    public override bool isMet()
    {
        return true;
    }
}

void Main()
{
    DerivedTrigger t = new DerivedTrigger();
    Serialize(t);
    ((Trigger)Deserialize()).isMet(); // returns True!
}

public static void Serialize<T>(T source)
{
    MemoryStream ms = new MemoryStream();
    Type serializedObjectType = typeof(T);

    DataContractSerializer dcsObject = new DataContractSerializer(serializedObjectType, null, int.MaxValue, false, true, null);

    dcsObject.WriteObject(ms, source); //serialize the object

    byte[] buffer = new byte[1024] //TODO:  adjust size
    ms.Position = 0;
    ms.Read(buffer, 0, 1024);

    //TODO: write buffer to database colObject here

    ms.Position = 0;
    DataContractSerializer dcsType = new DataContractSerializer(typeof(Type), null, int.MaxValue, false, true, null);
    dcsType.WriteObject(ms, serializedObjectType.DeclaringType);

    buffer = new byte[1024]
    ms.Position = 0;
    ms.Read(buffer, 0, 1024);

    //TODO: write buffer to database colType here
}

public static object Deserialize()
{
    MemoryStream ms = new MemoryStream();
    byte[] buffer = new byte[1024];

    //TODO: read colType into buffer here

    ms.Write(buffer, 0 1024);
    ms.Position = 0;

    DataContractSerializer dcsType = new DataContractSerializer(typeof(Type), null, int.MaxValue, false, true, null);
    Type serializedObjectType = dcs.Read(ms);

    //TODO: read colObject into buffer here

    DataContractSerializer dcs = new DataContractSerializer(serializedObjectType, null, int.MaxValue, false, true, null);
    return dcs.ReadObject(serializedObject);
}

编辑

好吧,使用MemoryStream似乎已经混淆了这种情况. MemoryStream不是存储在数据库中的东西,它是数据库.

拥有serializedObjectType的全部原因是因为,就像你说的那样,对DataContractSerializer中的类型使用typeof(Trigger)不会反序列化实际派生触发器的对象.因此,您需要将派生类型与对象一起存储在数据库中.

您还没有说过您正在使用的dbms,但我会使用blob来表示Trigger列,使用varbinary或blob来表示serializedObjectType列,即Trigger的实际派生类型.使用硬编码类型序列化器序列化类型.即DataContractSerializer(typeof(Type),…)并使用DataContractSerializer(typeof(T),…)序列化对象,其中T是可以使用泛型类型变量获得的派生触发器类型.

反序列化时,反向执行.首先使用硬编码类型序列化器对类型进行反序列化.即DataContractSerializer(typeof(Type),…)然后使用反序列化类型的结果反序列化对象.我已经更新了我的代码片段,希望能更好地说明我提出的策略.对不起我的回复迟到了.

编辑2

通常,在谈论序列化时,只序列化对象中的值,因为这是将一个对象与另一个对象分开的原因.您不需要将方法体序列化到数据库,因为它存储在文件系统的程序集中(您在问题中提到的可插入的dll).这些dll的加载是一个单独的步骤.查看System.Reflection.Assembly.LoadFile().

从你问题中的这两个陈述:

Trigger’s and Action’s need to be stored in a database.

…user’s to drop their own custom Trigger derived classes as a DLL into a specified folder..

我假设(可能不正确)类的定义将存储在fs中,并且进入每个类的对象的数据将存储在数据库中.如果派生的isMet()方法是静态的(可能不是显式的,但没有任何关联的状态),那么就不会有任何东西要存储在数据库中.但是,听起来你正在设置它,以便Trigger拥有一系列Actions.在这种情况下,那些Actions被序列化到数据库中.如果您的类是Serializable,则将它们标记为public,或者将该集合直接标记为Serializable.然后,存储器流的大小将与每个触发器保持的动作的数量成比例.像泥一样清楚?

点赞