Подскажите, как реализовать динамическое приведение типа базового класса к производному, когда заранее неизвестно, какой производный класс будет использоваться.
Собственно, имеем:
[Serializable]
class BaseMessage
{
public ulong ID;
public Type type;
}
[Serializable]
class Derived1<V> : BaseMessage
{
public V val;
public void Print1() { Console.Writeln("1"); }
}
[Serializable]
class Derived2<V> : BaseMessage
{
public List<V> val;
public void Print2() { Console.Writeln("2"); }
}
Сообщение типа 1 или 2 отправляется от клиента на сервер. Т.е. клиент сериализует объект класса Derived1<V> или Derived2<V> и отправляет.
Нужно что-то типа такого:
BaseMessage A = (BaseMessage)serializer.Deserialize(message);
var B = A as (A.t); //эта ветка когда понятно дело не работает.
При этом, допустим, получили Derived2<int> в B, хотим вызвать Print2(), получить значение поля val и т.п.
Здравствуйте, Нахлобуч, Вы писали:
Н>Здравствуйте, mitechka, Вы писали:
M>>Как это сделать?
Н>Какая реальная задача решается?
Есть клиент-сервер. Им необходимо общаться между собой. Сообщения могут быть разными — например, передача строки-команды на исполнение скрипта или передача некоторых данных произвольных типов. Для этого создаётся иерархия классов сообщений. Классы, реализующие клиентскую и серверную компоненты, имеют методы пересылки сообщений, которые принимают ссылку на базовый класс сообщений. Сами производные классы реализуют ISeriazible и IXmlSeriazible для корректной сериализации данных через произвольный сериализатор. Из-за того, что производные классы являются generic'ами, возникает проблема (иначе можно было бы использовать switch, хотя решение такого рода мне не нравится). Хочется как-то динамически преобразовывать в нужный тип и извлекать данные.
Может, есть какой bset practice для этого, чтобы не изобретать велосипед кривыми руками, то был бы рад услышать о таком.
Здравствуйте, mitechka, Вы писали:
M>Подскажите, как реализовать динамическое приведение типа базового класса к производному, когда заранее неизвестно, какой производный класс будет использоваться. M>Собственно, имеем: M>
M>[Serializable]
M>class BaseMessage
M>{
M> public ulong ID;
M> public Type type;
M>}
M>[Serializable]
M>class Derived1<V> : BaseMessage
M>{
M> public V val;
M> public void Print1() { Console.Writeln("1"); }
M>}
M>[Serializable]
M>class Derived2<V> : BaseMessage
M>{
M> public List<V> val;
M> public void Print2() { Console.Writeln("2"); }
M>}
M>
static void ProcessMessage(BaseMessage msg)
{
// do nothing
}
static void ProcessMessage<V>(Derived1<V> msg)
{
msg.Print1();
}
static void ProcessMessage<V>(Derived2<V> msg)
{
msg.Print2();
}
static void Main(string[] args)
{
var msg1 = new Derived1<int>();
var msg2 = new Derived2<string>();
ProcessMessage((dynamic)msg1);
ProcessMessage((dynamic)msg2);
}
Зачем нужно поле type — непонятно. Зачем generic-параметр V — тоже непонятно.
Вообще, конечно, это все велосипед велосипедом. Вот лишь одна из множества библиотек, реализующих функциональность полиморфной обработки сообщений.
Здравствуйте, mitechka, Вы писали:
M>Есть клиент-сервер. Им необходимо общаться между собой. Сообщения могут быть разными — например, передача строки-команды на исполнение скрипта или передача некоторых данных произвольных типов. ... Хочется как-то динамически преобразовывать в нужный тип и извлекать данные.
Зачем "динамически"? Что дальше с этими данными будете делать? Мне кажется, код должен знать, что и как делать с каждым конкретным классом сообщения. Или же передавайте IDictionary<string, object> и дело с концом.
HgLab: Mercurial Server and Repository Management for Windows
Здравствуйте, Нахлобуч, Вы писали:
Н>Здравствуйте, mitechka, Вы писали:
M>>Есть клиент-сервер. Им необходимо общаться между собой. Сообщения могут быть разными — например, передача строки-команды на исполнение скрипта или передача некоторых данных произвольных типов. ... Хочется как-то динамически преобразовывать в нужный тип и извлекать данные.
Н>Зачем "динамически"? Что дальше с этими данными будете делать? Мне кажется, код должен знать, что и как делать с каждым конкретным классом сообщения. Или же передавайте IDictionary<string, object> и дело с концом.
Дальше, собственно, работать с получаемыми данными. Вообще, наверное, иерархия туповата — каждый раз будет проблема с пониманием типа полученных данных, т.к. придётся ещё динамически определять тип V в дженериках для корректной работы с потрохами сообщений...
Здравствуйте, scale_tone, Вы писали:
_>Здравствуйте, mitechka, Вы писали:
M>>Подскажите, как реализовать динамическое приведение типа базового класса к производному, когда заранее неизвестно, какой производный класс будет использоваться. M>>Собственно, имеем: M>>
M>>[Serializable]
M>>class BaseMessage
M>>{
M>> public ulong ID;
M>> public Type type;
M>>}
M>>[Serializable]
M>>class Derived1<V> : BaseMessage
M>>{
M>> public V val;
M>> public void Print1() { Console.Writeln("1"); }
M>>}
M>>[Serializable]
M>>class Derived2<V> : BaseMessage
M>>{
M>> public List<V> val;
M>> public void Print2() { Console.Writeln("2"); }
M>>}
M>>
_>Зачем нужно поле type — непонятно. Зачем generic-параметр V — тоже непонятно.
_>Вообще, конечно, это все велосипед велосипедом. Вот лишь одна из множества библиотек, реализующих функциональность полиморфной обработки сообщений.
А можете привести пример или подсказать, как сделать систему классов "сообщений" для передачи между клиентом и сервером?
Задача такая: клиент и сервер общаются между собой сообщениями. Каждое сообщение — класс, содержащий UID, и некоторый набор данных (в зависимости от того, что пересылается). В качестве набора данных могут выступать вектора, матрицы, датафреймы, регулярки, строки или строкбилдеры (я пишу диспетчер многопоточного исполнения кода на R с помощью библиотеки R.NET). Хотелось бы понять, как сделать что-то универсальное. Можете дать ссылку на пример/статью/книгу, где можно почитать?
M>Задача такая: клиент и сервер общаются между собой сообщениями.
Положите в сообщение не просто класс но и тип его реалдизующий.
Если лень — выковыряйте тип из самого XML-а.
Здравствуйте, Tom, Вы писали:
M>>Задача такая: клиент и сервер общаются между собой сообщениями. Tom>Положите в сообщение не просто класс но и тип его реалдизующий. Tom>Если лень — выковыряйте тип из самого XML-а.
Tom>Положите в сообщение не просто класс но и тип его реалдизующий.
Здравствуйте, mitechka, Вы писали:
M>А можете привести пример или подсказать, как сделать систему классов "сообщений" для передачи между клиентом и сервером?
Система классов сообщений обычно ничем не отличается от просто системы классов. Все как у Вас: некий базовый класс, от него наследники с конкретными полями. Только поле type обычно в само сообщение не включают, а укладывают его вместе с сообщением в некий контейнер транспортного уровня (это если такое поле вообще нужно, т.е. если используемый сериализатор информацию о типах не поддерживает).
А дальше пишутся обработчики конкретных типов сообщений. И нужный обработчик ищется либо по старинке рефлекшеном (как в том же NServiceBus), либо с помощью IoC-контейнеров, либо вот с появлением слова dynamic стало возможно делать, как я написал в коде.
На самом деле, еще существует старинная концепция т.н. "бизнес-объектов". Это что-то вроде такого:
class BaseMessage
{
public ulong Id;
public virtual void ProcessMe()
{
// do nothing
}
}
class Derived1 : BaseMessage
{
public string FieldA { get; set; }
public override void ProcessMe()
{
Console.WriteLine("Processing Derived1 with FieldA = " + FieldA);
}
}
class Derived2 : BaseMessage
{
public DateTime FieldB { get; set; }
public override void ProcessMe()
{
Console.WriteLine("Processing Derived2 with FieldB = " + FieldB);
}
}
static void OnMessageReceived(BaseMessage msg)
{
msg.ProcessMe();
}
Т.е. когда код обработчиков запихивается в сами классы сообщений в виде виртуальных методов, и потому их (обработчики) не нужно искать.
И сейчас сюда набегут множество знающих людей, которые детально разъяснят, какая эта концепция ужасная и неправильная
M>Можете дать ссылку на пример/статью/книгу, где можно почитать?
Здравствуйте, scale_tone, Вы писали:
_>Здравствуйте, mitechka, Вы писали:
M>>А можете привести пример или подсказать, как сделать систему классов "сообщений" для передачи между клиентом и сервером?
_>Система классов сообщений обычно ничем не отличается от просто системы классов. Все как у Вас: некий базовый класс, от него наследники с конкретными полями. Только поле type обычно в само сообщение не включают, а укладывают его вместе с сообщением в некий контейнер транспортного уровня (это если такое поле вообще нужно, т.е. если используемый сериализатор информацию о типах не поддерживает).
_>А дальше пишутся обработчики конкретных типов сообщений. И нужный обработчик ищется либо по старинке рефлекшеном (как в том же NServiceBus), либо с помощью IoC-контейнеров, либо вот с появлением слова dynamic стало возможно делать, как я написал в коде.
_>На самом деле, еще существует старинная концепция т.н. "бизнес-объектов". Это что-то вроде такого: _>
_> class BaseMessage
_> {
_> public ulong Id;
_> public virtual void ProcessMe()
_> {
_> // do nothing
_> }
_> }
_> class Derived1 : BaseMessage
_> {
_> public string FieldA { get; set; }
_> public override void ProcessMe()
_> {
_> Console.WriteLine("Processing Derived1 with FieldA = " + FieldA);
_> }
_> }
_> class Derived2 : BaseMessage
_> {
_> public DateTime FieldB { get; set; }
_> public override void ProcessMe()
_> {
_> Console.WriteLine("Processing Derived2 with FieldB = " + FieldB);
_> }
_> }
_> static void OnMessageReceived(BaseMessage msg)
_> {
_> msg.ProcessMe();
_> }
_>
_>Т.е. когда код обработчиков запихивается в сами классы сообщений в виде виртуальных методов, и потому их (обработчики) не нужно искать. _>И сейчас сюда набегут множество знающих людей, которые детально разъяснят, какая эта концепция ужасная и неправильная
M>>Можете дать ссылку на пример/статью/книгу, где можно почитать?
_>Как раз недавно был срач диспут, со ссылками на литературу
Здравствуйте, mitechka, Вы писали:
M>Подскажите, как реализовать динамическое приведение типа базового класса к производному, когда заранее неизвестно, какой производный класс будет использоваться.
M>Сообщение типа 1 или 2 отправляется от клиента на сервер. Т.е. клиент сериализует объект класса Derived1<V> или Derived2<V> и отправляет.
Здравствуйте, mitechka, Вы писали:
M>Здравствуйте, Нахлобуч, Вы писали:
Н>>Здравствуйте, mitechka, Вы писали:
M>>>Как это сделать?
Н>>Какая реальная задача решается?
M>Есть клиент-сервер. Им необходимо общаться между собой. Сообщения могут быть разными — например, передача строки-команды на исполнение скрипта или передача некоторых данных произвольных типов. Для этого создаётся иерархия классов сообщений. Классы, реализующие клиентскую и серверную компоненты, имеют методы пересылки сообщений, которые принимают ссылку на базовый класс сообщений. Сами производные классы реализуют ISeriazible и IXmlSeriazible для корректной сериализации данных через произвольный сериализатор. Из-за того, что производные классы являются generic'ами, возникает проблема (иначе можно было бы использовать switch, хотя решение такого рода мне не нравится). Хочется как-то динамически преобразовывать в нужный тип и извлекать данные. M>Может, есть какой bset practice для этого, чтобы не изобретать велосипед кривыми руками, то был бы рад услышать о таком.
M>Спасибо.
Основное различие между сериализаторами DataContractSerializer и NetDataContractSerializer заключается в том, что DataContractSerializer использует имена контракта данных, а NetDataContractSerializer выводит полную сборку .NET Framework и имена типов в сериализованном XML-коде. Это означает, что одни и те же типы должны совместно использоваться конечными точками сериализации и десериализации. Так как при использовании сериализатора NetDataContractSerializer всегда известны точные типы, которые должны быть десериализованы, механизм известных типов не требуется.
и солнце б утром не вставало, когда бы не было меня
S>Основное различие между сериализаторами DataContractSerializer и NetDataContractSerializer заключается в том, что DataContractSerializer использует имена контракта данных, а NetDataContractSerializer выводит полную сборку .NET Framework и имена типов в сериализованном XML-коде. Это означает, что одни и те же типы должны совместно использоваться конечными точками сериализации и десериализации. Так как при использовании сериализатора NetDataContractSerializer всегда известны точные типы, которые должны быть десериализованы, механизм известных типов не требуется.
Да я смотрел в сторону NetDataContractSerializer'а, но, к сожалению, на другой стороне же необходимо приводить базовый класс к производному, тип которого заранее неизвестен, а сериалайзер не умеет конструировать объекты произвольного типа.
Здравствуйте, agat50, Вы писали:
A>Здравствуйте, mitechka, Вы писали:
M>>Здравствуйте, Нахлобуч, Вы писали:
Н>>>Здравствуйте, mitechka, Вы писали:
M>>>>Как это сделать?
Н>>>Какая реальная задача решается?
M>>Есть клиент-сервер. Им необходимо общаться между собой. Сообщения могут быть разными — например, передача строки-команды на исполнение скрипта или передача некоторых данных произвольных типов. Для этого создаётся иерархия классов сообщений. Классы, реализующие клиентскую и серверную компоненты, имеют методы пересылки сообщений, которые принимают ссылку на базовый класс сообщений. Сами производные классы реализуют ISeriazible и IXmlSeriazible для корректной сериализации данных через произвольный сериализатор. Из-за того, что производные классы являются generic'ами, возникает проблема (иначе можно было бы использовать switch, хотя решение такого рода мне не нравится). Хочется как-то динамически преобразовывать в нужный тип и извлекать данные. M>>Может, есть какой bset practice для этого, чтобы не изобретать велосипед кривыми руками, то был бы рад услышать о таком.
M>>Спасибо.
A>http://james.newtonking.com/archive/2010/08/13/json-net-3-5-release-8-3-5-final?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+jamesnewtonking+%28James+Newton-King%29
A>Мб не поздно перейти.
Мммм... А в библиотеке есть возможность привести динамически тип по переданному в переменной типу класса?
S>>Основное различие между сериализаторами DataContractSerializer и NetDataContractSerializer заключается в том, что DataContractSerializer использует имена контракта данных, а NetDataContractSerializer выводит полную сборку .NET Framework и имена типов в сериализованном XML-коде. Это означает, что одни и те же типы должны совместно использоваться конечными точками сериализации и десериализации. Так как при использовании сериализатора NetDataContractSerializer всегда известны точные типы, которые должны быть десериализованы, механизм известных типов не требуется.
M>Да я смотрел в сторону NetDataContractSerializer'а, но, к сожалению, на другой стороне же необходимо приводить базовый класс к производному, тип которого заранее неизвестен, а сериалайзер не умеет конструировать объекты произвольного типа.
NetDataContractSerializer'а
Как раз умеет. Умеет это и datacontractserializer с известными типами
Ты ссылки смотрел?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, mitechka, Вы писали:
M>Да я смотрел в сторону NetDataContractSerializer'а, но, к сожалению, на другой стороне же необходимо приводить базовый класс к производному, тип которого заранее неизвестен, а сериалайзер не умеет конструировать объекты произвольного типа.
Для интереса сделал иерархию
namespace test
{
[DataContract]
public abstract class Base
{
[DataMember]
public string BaseName { get; set; }
}
[DataContract]
public class MyClass1 : Base
{
[DataMember]
public string Поле1 { get; set; }
}
И соответственно сериализация десериализация
var child = new test.MyClass1();
child.Поле1 = "MyClass1";
// here is where I went wrong before -- I used typeof(Child), with no known types to serializevar serializer = new DataContractSerializer(typeof(object), new Type[] { typeof(test.MyClass1) });
var stream = new MemoryStream();
serializer.WriteObject(stream, child);
stream.Position = 0;
TextReader tr = new StreamReader(stream);
var str = tr.ReadToEnd();
stream.Position = 0;
serializer = new DataContractSerializer(typeof(object), new Type[] { typeof(test.MyClass1) });
object test = serializer.ReadObject(stream);
stream.Dispose();
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, mitechka, Вы писали:
M>>Да я смотрел в сторону NetDataContractSerializer'а, но, к сожалению, на другой стороне же необходимо приводить базовый класс к производному, тип которого заранее неизвестен, а сериалайзер не умеет конструировать объекты произвольного типа.
S>Для интереса сделал иерархию S>
S>namespace test
S>{
S> [DataContract]
S> public abstract class Base
S> {
S> [DataMember]
S> public string BaseName { get; set; }
S> }
S> [DataContract]
S> public class MyClass1 : Base
S> {
S> [DataMember]
S> public string Поле1 { get; set; }
S> }
S>
S>И соответственно сериализация десериализация
S>
S> var child = new test.MyClass1();
S> child.Поле1 = "MyClass1";
S> // here is where I went wrong before -- I used typeof(Child), with no known types to serialize
S> var serializer = new DataContractSerializer(typeof(object), new Type[] { typeof(test.MyClass1) });
S> var stream = new MemoryStream();
S> serializer.WriteObject(stream, child);
S> stream.Position = 0;
S> TextReader tr = new StreamReader(stream);
S> var str = tr.ReadToEnd();
S> stream.Position = 0;
S> serializer = new DataContractSerializer(typeof(object), new Type[] { typeof(test.MyClass1) });
S> object test = serializer.ReadObject(stream);
S> stream.Dispose();
S>
Ммм... Хорошо, тогда вопрос — если потомков 2, каждый из них — дженерик, то как определить и привести полученное сообщение именно к нужному потомку? Собственно, основной проблемой для меня было именно это...
M>Ммм... Хорошо, тогда вопрос — если потомков 2, каждый из них — дженерик, то как определить и привести полученное сообщение именно к нужному потомку? Собственно, основной проблемой для меня было именно это...
Так попробуй NetDataContractSerializer. Главное, что бы сборки классов были на клиенте и на сервере или в гаке
Он сам десериализует в нужный объект.
и солнце б утром не вставало, когда бы не было меня