Cast структур.
От: xorix  
Дата: 16.11.15 22:40
Оценка:
Добрый день!
Подскажите пожалуйста есть ли какие-либо варианты реализации. Нужно реализовать следующую логику (ниже). В моем случае компилятор выдает ошибку, что и понятно.
Но непонятно как сделать так, чтоб эта логика работала. Важный момент, в моем случае я не могу переделать МyStruct1 на класс, это должна быть именно структура.

public interface IMessage
{
int GetMessageType();
}

struct MyStruct1 : IMessage
{
public int GetMessageType()
{
return 1;
}
}

struct MyStruct2 : IMessage
{
public int GetMessageType()
{
return 2;
}
}

public interface IObject
{
void OnReceive<T>(ref T message_) where T : IMessage;
}

class TestClass : IObject
{
public void OnReceive<T>(ref T message_) where T : IMessage
{
int type = message_.GetMessageType();
switch (type)
{
case 1: OnReceiveMessage(ref message_); break; // error CS1502: The best overloaded method match for 'Test.TestClass.OnReceiveMessage(ref Test.MyStruct1)' has some invalid arguments
}
}

public void OnReceiveMessage(ref MyStruct1 message_)
{
}
}
Re: Cast структур.
От: xorix  
Дата: 16.11.15 22:57
Оценка:
Странно, что так:

class TestClass : IObject
{
public void OnReceive<T>(ref T message_)
{
OnReceiveMessage(ref message_);
}

public void OnReceiveMessage(ref MyStruct1 message_)
{
}

public void OnReceiveMessage<T>(ref T message_)
{
}
}

Он вызывает именно OnReceiveMessage<T>(ref T message_), а не OnReceiveMessage(ref MyStruct1 message_), хотя я явно туда передаю MyStruct1
Re: Cast структур.
От: xorix  
Дата: 17.11.15 00:05
Оценка:
Ничего лучше этого не смог придумать (ниже), но тут на каждую структуру по выделению памяти происходит. Если кто что придумает пишите.

public class XMessage<T> where T : IMessage
{
public T m_Message;
};

public interface IObject
{
void OnReceive<T>(XMessage<T> message_) where T : IMessage;
}

class TestClass : IObject
{
public void OnReceive<T>(XMessage<T> message_) where T : IMessage
{
int type = message_.m_Message.GetMessageType();
if (type == 1)
OnReceiveMessage(message_ as XMessage<MyStruct1>);
}

public bool OnReceiveMessage(XMessage<MyStruct1> message_)
{
return true;
}
}
Re: Cast структур.
От: Sinix  
Дата: 17.11.15 05:59
Оценка: +1
Здравствуйте, xorix, Вы писали:

X>Добрый день!

X>Подскажите пожалуйста есть ли какие-либо варианты реализации. Нужно реализовать следующую логику (ниже). В моем случае компилятор выдает ошибку, что и понятно.
X>Но непонятно как сделать так, чтоб эта логика работала. Важный момент, в моем случае я не могу переделать МyStruct1 на класс, это должна быть именно структура.

1. Изучаем, как работают генерики
il-код верифицируется на этапе компиляции, разрешение перегрузок происходит тогда же. Реальные типы подставляются позже, в рантайме.
Компилятор не может гарантировать, что тип T будет всегда MyStruct1 и посылает код лесом.

2. Использование ref-параметров без явной и очевидной причины является плохой практикой и приводит к очень неприятным сюрпризам. Особенно если передаётся базовый тип. В частности, поэтому компилятор не позволяет трюки вида
public void DoDarkMagic(ref Control control)
{
    control = new TextBox();
}

public void Main()
{
    Button button = new Button();

    DoDarkMagic(ref button);

    // Now your button magically became a text box ...
}


3. Начните проектировать APT от сценариев использования. Очень помогает от ситуаций "ух что придумал! Менять всё поздно, но как это теперь использовать?"
Re[2]: Cast структур.
От: Sinix  
Дата: 17.11.15 06:08
Оценка:
Здравствуйте, xorix, Вы писали:

X>Ничего лучше этого не смог придумать (ниже), но тут на каждую структуру по выделению памяти происходит. Если кто что придумает пишите.


1. Читаем Рихтера По выделению памяти тут не происходит.

2. Вам здесь вообще T не нужно. Заведите базовый класс без генерик-параметра и кастьте его к нужному вам типу.
или используйте
dynamic x = message;
OnReceiveMessage(x); // разрешение перегрузок будет происходить в рантайме
Re[3]: Cast структур.
От: xorix  
Дата: 17.11.15 15:22
Оценка:
>> 1. Читаем Рихтера По выделению памяти тут не происходит.
Происходит, я просто не написал код где это происходит. У меня приезжает структура и соответственно если бы я дальше передавал структуру
то все было бы на стеке. А так обарачивая структуру в мембер класса, клас создается в хипе, соответственно на каждую приезжающую структуру
выделяется память под калсс и структуру.

>>dynamic x = message;

Про dynamic спасибо, попробую. А не подскажите dynamic своим поздним связыванием не будет аффектить перфоманс?
Re[4]: Cast структур.
От: Sinix  
Дата: 18.11.15 05:41
Оценка:
Здравствуйте, xorix, Вы писали:

X>А так обарачивая структуру в мембер класса, клас создается в хипе, соответственно на каждую приезжающую структуру

X>выделяется память под калсс и структуру.
Не совсем так, отдельная память под структуру не выделяется, в самом экземпляре класса хранится.

>>>dynamic x = message;

X>Про dynamic спасибо, попробую. А не подскажите dynamic своим поздним связыванием не будет аффектить перфоманс?
Нет. В своё время проверял — сопоставимо с поиском в словаре и вызовом делегата. Но ничего не мешает перепроверить самому
Re[5]: Cast структур.
От: xorix  
Дата: 18.11.15 21:23
Оценка:
X>>А так обарачивая структуру в мембер класса, клас создается в хипе, соответственно на каждую приезжающую структуру
X>>выделяется память под калсс и структуру.
S>Не совсем так, отдельная память под структуру не выделяется, в самом экземпляре класса хранится.

Да, все верно вы говорите, но я имел ввиду немного другое, что память будет выделяться под класс, т.е.:

вместо того чтоб просто дальше передать структуру:

void test(ref Message msg)
{
nextFunc(ref msg)
}

мне надо будет сделать:

void test(ref Message msg)
{
Boxing<Message> boxingMsg = new Boxing<Message>(msg);
nextFunc(boxingMsg);
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.