Вместо использования метода isMet()
для базового Trigger
класса abstract
установите его virtual
, возможно, значением по умолчанию является false.Затем вы можете override
метод в производных классах, используя ключевое слово override
.
Ваша вторая проблема касается сериализации и десериализации триггеров для базы данных.Когда вы десериализуете, вы хотите убедиться, что вы возвращаете производный тип триггера, а не базовый.Я не знаю, как вы решили сериализовать ваши объекты в базе данных, но вам понадобится способ сохранить тип.Например, DataContractSerializer
.Он принимает Type
в качестве первого параметра.Если вы сохраните typeof (DerivedTrigger) в другом поле в вашей базе данных при сериализации триггеров, вы можете десериализовать тип и использовать его для десериализации триггера до правильного производного типа.Затем вызов вашего isMet()
метода должен вызвать производное переопределенное значение.Вот краткий пример использования статических переменных вместо базы данных:
[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);
}
EDIT
Хорошо, использование MemoryStream, похоже, запутало ситуацию.MemoryStream - это не то, что хранится в базе данных, это база данных.
Вся причина наличия serializedObjectType
состоит в том, что, как вы говорите, использование typeof(Trigger)
для типа в DataContractSerializer выигралоне десериализовать объекты, которые на самом деле являются производными триггерами.Следовательно, вам необходимо сохранить производный тип вместе с объектом в базе данных.
Вы не сказали, какие dbms вы используете, но я бы использовал BLOB-объект для представления столбца Trigger и либо varbinaryили большой двоичный объект для представления столбца serializedObjectType
, то есть фактического наиболее производного типа триггера.Сериализуйте тип с помощью жестко закодированного сериализатора типа.то есть DataContractSerializer(typeof(Type), ...)
и сериализовать объект с DataContractSerializer(typeof(T), ...)
, где T - это производный тип триггера, который вы можете получить с помощью переменной универсального типа.
Когда вы десериализуетесь, сделайте это в обратном порядке.Сначала десериализуйте тип, используя жестко закодированный сериализатор типов.то есть DataContractSerializer(typeof(Type), ...)
, а затем десериализовать объект с результатами десериализованного типа.Я обновил свои фрагменты кода, чтобы, надеюсь, лучше проиллюстрировать предложенную мной стратегию.Извините за задержку в моем ответе.
РЕДАКТИРОВАТЬ 2
Обычно, когда речь идет о сериализации, вы сериализуете только значения в объекте, поскольку именно это разделяет однообъект от другого.Вам не нужно сериализовать тело метода в базу данных, потому что оно хранится в сборках в файловой системе (подключаемые библиотеки, которые вы упоминаете в своем вопросе).Загрузка этих библиотек является отдельным шагом все вместе.посмотрите на System.Reflection.Assembly.LoadFile()
.
Из этих двух утверждений в вашем вопросе:
Триггеры и действия должны храниться в базе данных.
и
... пользователь должен удалить свои собственные классы, производные от триггера, в виде DLL в указанную папку.
Я предположил (возможно, неправильно), что определение длякласс будет храниться в фс, а данные, которые поступают в объекты каждого класса, будут храниться в базе данных.Если ваши производные isMet()
методы являются статическими (может быть, не явно, но не имеют никакого связанного состояния), то в базе данных не будет ничего хранить.Однако, похоже, что вы настраиваете его так, что Trigger
содержит коллекцию Actions
.В этом случае эти Actions
- это то, что сериализуется в базу данных.Просто отметьте их как общедоступные, если ваш класс Serializable
, или пометьте коллекцию непосредственно как Serializable
.Таким образом, размер потока памяти будет пропорционален числу Actions
каждого триггера.Ясно, как грязь?