|
Виж темите без отговор | Виж активните теми
Дата и час: Пон Юли 27, 2026 7:15 am
|
Страница 1 от 1
|
[ 7 мнения ] |
|
Предаване на параметър на метод по стойност в C#
| Автор |
Съобщение |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
 Предаване на параметър на метод по стойност в C#
C# по подразбиране предава параметрите на методите по адрес (reference), изключения са базовите типове данни (int, double, string и т.н.), както и прости структури (които нямат масиви например). Имам следната C# структура: Тази структура ще се добавя от работна нишка в стандартна System.Collections.Generic.Queue, след което сигнализира главната нишка за последваща обработка. Направих нещо съвсем просто: заделих памет за TPCANMsg в работната нишка и всеки път когато дойдат данни ги копирам в нейните полета, след което викам Queue.Enqueue(msg). Понеже DATA[] е масив, C# го предава на Enqueue() като адрес и съответно в опашката всички предходни елементи се променят, което не искам да бъде така. Целият код е по-долу:  |  |  |  | Код: public void PrintPCANMsg(TPCANMsg msg) { string szHex = Convert.ToString(msg.ID, 16); szHex = szHex.ToUpper(); Console.WriteLine("ID: 0x{0}; LEN: {1}; DATA[]:" + " 0x{2:X}, 0x{3:X}, 0x{4:X}, 0x{5:X}, 0x{6:X}, 0x{7:X}, 0x{8:X}, 0x{9:X}", szHex, msg.LEN, msg.DATA[0], msg.DATA[1], msg.DATA[2], msg.DATA[3], msg.DATA[4], msg.DATA[5], msg.DATA[6], msg.DATA[7]); }
public void QueueTest() { Queue<TPCANMsg> queue = new Queue<TPCANMsg>(); TPCANMsg msg = new TPCANMsg(); msg.DATA = new byte[8];
Console.WriteLine("Enqueue() method: ");
msg.LEN = 8; msg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD; /// Enqueue 1st msg /// msg.DATA[0] = 0x11; msg.DATA[1] = 0x12; msg.DATA[2] = 0x13; msg.DATA[3] = 0x14; msg.DATA[4] = 0x15; msg.DATA[5] = 0x16; msg.DATA[6] = 0x17; msg.DATA[7] = 0x18; msg.ID = 0x18FFD61E;
queue.Enqueue(msg); PrintPCANMsg(msg);
/// Enqueue 2nd msg /// msg.DATA[0] = 0x21; msg.DATA[1] = 0x22; msg.DATA[2] = 0x23; msg.DATA[3] = 0x24; msg.DATA[4] = 0x25; msg.DATA[5] = 0x26; msg.DATA[6] = 0x27; msg.DATA[7] = 0x28; msg.ID = 0x18FFE01E; queue.Enqueue(msg); PrintPCANMsg(msg);
/// Dequeue and Print all messages /// Console.WriteLine("Dequeue() method: "); while ( queue.Count > 0 ) { msg = queue.Dequeue(); PrintPCANMsg(msg); } }
|  |  |  |  |
Резултата от кода:  |  |  |  | Код: Enqueue() method: ID: 0x18FFD61E; LEN: 8; DATA[]: 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 ID: 0x18FFE01E; LEN: 8; DATA[]: 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28 Dequeue() method: ID: 0x18FFD61E; LEN: 8; DATA[]: 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28 ID: 0x18FFE01E; LEN: 8; DATA[]: 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28
|  |  |  |  |
Както се вижда от резултата C# е подал DATA[] масива като адрес, затова изваждайки двата елемента имам еднакви DATA[], докато ID е наред. Най-тъпото което се сетих е да променя структурата така: След което при Enqueue() и Dequeue() с опашката всичко е наред, понеже този път в структурата няма масив и C# я предава като параметър по стойност. Не ми се ще обаче да имам такава междинна структура, искам да е оригиналната с масив в нея. Има ли начин на C# да се укаже да предаде структура/клас като параметър на метод по стойност ? Ако няма, как постъпвате когато трябва да предадете по стойност ?
_________________ Ето аз дишам, работя, живея и програми пиша тъй както умея, с проца под вежди се гледаме строго и боря се с него доколкото мога....
|
| Пет Окт 15, 2021 6:07 pm |
|
 |
|
slav4o.com
Ранг: Форумен бог
Регистриран на: Нед Яну 01, 2012 8:04 pm Мнения: 2663 Местоположение: София / Велико Търново
|
 Re: Предаване на параметър на метод по стойност в C#
Ами видимо имаш само един физически създаден масив msg.DATA = new byte[8]; при Dequeue() пак дърпаш "неговата инстанция", фактически нашиваш данните два пъти на едно място и при Dequeue() дърпаш последните данни. .... Според мен трябва на второто зареждане на данни за тест, да напишеш още веднъж msg.DATA = new byte[8]; и да инициализираш новите данни. Така ще имаш 2 физически масива в паметта които да държат данните. edit: Ако данните за масива идват от масив, може да използваш Array.Copy да не ги зареждаш с цикъл елемент по елемент. То този метод сигурно така работи де...
|
| Пет Окт 15, 2021 7:43 pm |
|
 |
|
palavrov
Ранг: Форумен бог
Регистриран на: Вто Окт 11, 2011 11:53 pm Мнения: 4582 Местоположение: Brussels / Пловдив
|
 Re: Предаване на параметър на метод по стойност в C#
Трябва да си направиш shallow или deep clone на обекта - пусни едни гугле и ще намериш достатъчно страници как да подкараш всичко.
_________________ Мразя да мразя ...
|
| Нед Окт 17, 2021 6:36 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
 Re: Предаване на параметър на метод по стойност в C#
Благодаря за отговорите. Всъщност бях разбрал, че му липсва , но по скоро ме интересуваше някакъв друг начин. Ще видя тези shallow и deep clone, но видях че C# предлага и още един начин, fixed: но при компилиране дава грешка: Добавям unsafe към дефиницията на структурата: и сега се оплаква, че: Та сега въпроса ми е: fixed и unsafe за структурата, компилирам проекта като unsafe и работи под Windows, но това unsafe/fixed дали няма да създаде подводни камъни при билдване на други платформи ? C# е малко като манджа с грозде 
_________________ Ето аз дишам, работя, живея и програми пиша тъй както умея, с проца под вежди се гледаме строго и боря се с него доколкото мога....
|
| Пон Окт 18, 2021 4:32 pm |
|
 |
|
slav4o.com
Ранг: Форумен бог
Регистриран на: Нед Яну 01, 2012 8:04 pm Мнения: 2663 Местоположение: София / Велико Търново
|
 Re: Предаване на параметър на метод по стойност в C#
Ами когато включиш unsafe опцията вече може и така да стане  Доколкото виждам struct във C# еквивалентно на typedef struct във C/C++. T.e. това не е обект а сложен тип. Т.е. трябва да напишеш нещо от сорта на myStruct CANMsg; naBaiIvanStructurata CANMsg; Всъщност защо не използваш само класове ? Принципно всеки метод получава аргументите по стойност. Референтните типове са пак стойност която държи тип и адрес на обекта към който сочат. За да може реално Dequeue() да извлече данните обекта който се подава на Queue() трябва да съществува в паметта във момента на Dequeue() така той реално ще съхранява физически въпросният масив, а в опашката ще имаш референция към него. Ако обектът който се подава на Queue() е Dispose()-нат към момента на Dequeue() естествено трябва да си правиш локални копия в твоите обекти от опашката. 
|
| Пон Окт 18, 2021 8:51 pm |
|
 |
|
¶
Ранг: Форумен бог
Регистриран на: Пет Фев 25, 2005 1:58 pm Мнения: 4585 Местоположение: US
|
 Re: Предаване на параметър на метод по стойност в C#
Не ползвам само класове, защото чета от C++ DLL, и там данните са struct.
_________________ Ето аз дишам, работя, живея и програми пиша тъй както умея, с проца под вежди се гледаме строго и боря се с него доколкото мога....
|
| Вто Окт 19, 2021 2:03 pm |
|
 |
|
valioman
Ранг: Почетен член
Регистриран на: Съб Сеп 17, 2005 5:07 pm Мнения: 813 Местоположение: Сливен
|
 Re: Предаване на параметър на метод по стойност в C#
Добре си се сетил за unsafe .. по принцип щом ти ще си менаджираш паметта с подобни гимнастики трябва да го кажеш на билдера. Отиваш на Properties на проекта и цъкаш отметката AllowUnsafeCode от Build менюто
|
| Сря Окт 20, 2021 10:24 pm |
|
|
|
Страница 1 от 1
|
[ 7 мнения ] |
|
Кой е на линия |
Потребители разглеждащи този форум: 0 регистрирани и 2 госта |
|
Вие не можете да пускате нови теми Вие не можете да отговаряте на теми Вие не можете да променяте собственото си мнение Вие не можете да изтривате собствените си мнения Вие не можете да прикачвате файл
|
|