Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
S>>Не знаю, зачем такое может понадобиться, но всёж.
V>Для интеропа часто использую. V>Интероп требует передавать структуры по указателю в некое АПИ, но: V>- иногда хочется оставить их value-типами; V>- иногда требуется подать NULL; V>- раскидывать unmanaged/fixed повсюду не хочется.
Перегрузка с IntPtr или ссылочным типом не решит проблему ?
struct A { public int i;}
[DllImport("a.dll")
static extern void f(ref A a);
[DllImport("a.dll")
static extern void f(IntPtr a);
class Null { private Null() {} public static Null Null = null; }
[DllImport("a.dll")
static extern void f(Null @null);
Здравствуйте, Sharov, Вы писали:
V>>int select(int, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const timeval *timeout) V>>будет комбинаторика из 12 допустимых сочетаний с NULL плюс один без NULL. S>И в чем проблема?
В очевидной упоротости, при наличии простого как 3 копейки альтернативного решения.
Вроде бы в будущем C# 8.0 решили уже — через ref ?.
Т.е. обычные ссылки строго ненуллабельные, а с вопросиком нуллабельные.
Ну и чудесно, как по мне.
Тем более, что в отличие от C++, ref-переменные в C# имеют семантику не ссылок, а именно указателей, бо в С++ ссылка — это алиас, а в C# — значение, т.е. которое запросто можно перезаписать. И семантика управляемого указателя на value-type всё-равно была нужна, вот как раз эта семантика будет обладать полнотой, коль NULL будет валидным значением для nullable-ссылок.
Здравствуйте, vdimas, Вы писали:
V>Тем более, что в отличие от C++, ref-переменные в C# имеют семантику не ссылок, а именно указателей, бо в С++ ссылка — это алиас, а в C# — значение, т.е. которое запросто можно перезаписать. И семантика управляемого указателя на value-type всё-равно была нужна, вот как раз эта семантика будет обладать полнотой, коль NULL будет валидным значением для nullable-ссылок.
В обычном коде да, но мы про P/Invoke.
Код компилируется, но не работает.
Передать Nullable на данный момент нет возможности из-за ограничения на обобщённый тип:
public struct HWND { IntPtr hwnd; }
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(HWND? hWnd, String text, String caption, int options);
static void Main(string[] args)
{
MessageBox(null, null, null, 0);
}
Здравствуйте, _NN_, Вы писали:
_NN>Код компилируется, но не работает. _NN>Передать Nullable на данный момент нет возможности из-за ограничения на обобщённый тип:
Это C# 8.0?
Насколько я понял, для GC-типов '?' будет директивой компилятору, а не заворачивание в struct Nullable<T> where T : struct.
Здравствуйте, vdimas, Вы писали:
V>Тем более, что в отличие от C++, ref-переменные в C# имеют семантику не ссылок, а именно указателей, бо в С++ ссылка — это алиас, а в C# — значение, т.е. которое запросто можно перезаписать.
Не вижу принципиального различия в этом описании. Вообще не вижу особых отличий между ссылками в C++ и ref-ссылками в C#. Для меня то и другое ― алиас. Если для указателя любое значение нормально, оно может меняться во времени (арифметика указателей), а null — естественное значение по умолчанию, то ссылка, если уж возникла, должна указывать на что-то реально существующее. Ссылка на null — мне это дико что в C++, что в C#.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, _NN_, Вы писали:
_NN>>Код компилируется, но не работает. _NN>>Передать Nullable на данный момент нет возможности из-за ограничения на обобщённый тип:
V>Это C# 8.0? Да. В C# 7.3 это не соберётся
V>Насколько я понял, для GC-типов '?' будет директивой компилятору, а не заворачивание в struct Nullable<T> where T : struct.
Тут 'HWND?' означает Nulalble<HWND> потому как struct HWND.
Здравствуйте, alexzzzz, Вы писали:
V>>Тем более, что в отличие от C++, ref-переменные в C# имеют семантику не ссылок, а именно указателей, бо в С++ ссылка — это алиас, а в C# — значение, т.е. которое запросто можно перезаписать.
A>Не вижу принципиального различия в этом описании. Вообще не вижу особых отличий между ссылками в C++ и ref-ссылками в C#. Для меня то и другое ― алиас. Если для указателя любое значение нормально, оно может меняться во времени (арифметика указателей), а null — естественное значение по умолчанию, то ссылка, если уж возникла, должна указывать на что-то реально существующее. Ссылка на null — мне это дико что в C++, что в C#.
Ну вот сам себе и ответил.
Значение ссылки в C# можно изменять.
И для них есть адресная арифметика.
Похоже, тебя смущает одноимённость именований разных сущностей в разных языках.
Здравствуйте, _NN_, Вы писали:
V>>Насколько я понял, для GC-типов '?' будет директивой компилятору, а не заворачивание в struct Nullable<T> where T : struct. _NN>Тут 'HWND?' означает Nulalble<HWND> потому как struct HWND.
О чём и речь, т.е. пример неудачный или неудачный пример его использования.
Чтобы в твоём примере подать NULL в Interop, достаточно сделать так:
MessageBox(default, "blah-blah"...
ref-ссылки на value-type имеет смысл только когда передаются указатели на составные типы данных (структуры), хендлы к таковым не относится.
Здравствуйте, vdimas, Вы писали:
V>О чём и речь, т.е. пример неудачный или неудачный пример его использования.
Ну HWND это понятно для примера, пусть будет struct MyStructure.
V>Чтобы в твоём примере подать NULL в Interop, достаточно сделать так: V>
V>MessageBox(default, "blah-blah"...
V>
Это компилируется но падает с той же ошибкой, передать Nullable<> нельзя.
Здравствуйте, _NN_, Вы писали:
V>>Чтобы в твоём примере подать NULL в Interop, достаточно сделать так: V>>MessageBox(default, "blah-blah"... _NN>Это компилируется но падает с той же ошибкой, передать Nullable<> нельзя.
Ес-но. ))
Имелось ввиду:
public struct HWND { IntPtr hwnd; }
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(HWND hWnd, string text, string caption, int options);
static void Main(string[] args)
{
MessageBox(default, "World!!!", "Hello", 0);
}
Здравствуйте, vdimas, Вы писали:
V>Только что проверил — работает на ура в C# 7.3.
Ну так это совершенно другой пример и работает по другой причине
default(HWND) в памяти представлен нулями и трактуя это как указатель получаем нулевой указатель.
Здравствуйте, vdimas, Вы писали:
V>Ну вот сам себе и ответил. V>Значение ссылки в C# можно изменять. V>И для них есть адресная арифметика.
V>Похоже, тебя смущает одноимённость именований разных сущностей в разных языках.
Может, это ты про что-то другое?
В C# переменные могут быть трёх типов: value-, reference- и указатели. По умолчанию передаются/копируются/присваиваются по значению, но при помощи ключевого слова ref можно получать ссылки на эти переменные. Речь про эти ref-ссылки. Какая же у них адресная арифметика?
int a = 100;
int[] b = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ref int r = ref a;
r++;
r = ref b[5];
r++;
r — это алиас сначала для a, потом для b[5]. Все манипуляции с r будут происходить с a и b[5]. Максимум что можно сделать с самой ссылкой, перенаправить её в новое место, явно указав, куда именно; а не как с указателями, где можно прибавить к адресу левое число — авось куда-нибудь да попадём.
Указатель подразумевает, что есть непревырвая последовательность ячеек памяти, которые можно последовательно или произвольно читать и писать. Указатель может смотреть на любую ячейку. Лежат ли в ней полезные данные, какой-то мусор или access violation — не его забота. Аналогия указателя — индекс в массиве. Знаешь индекс элемента — можешь обращаться к нему, к соседям, вылезти за пределы массива тоже можешь.
Ссылка же указывает на какую-то конкретную ячейку памяти, в которой гарантированно хранится что-то полезное. Существование других ячеек не подразумевается. Адресной арифметики нет. Ссылка не обязана быть адресом — это деталь реализации. Аналогия ссылки — ключ в словаре. Знаешь ключ — имеешь доступ только к соответствующему значению и всё.
Поэтому null-ссылка, которая никуда не указывает, на первый взгляд кажется бредом. Хотя технически возможна и в C# и в С++.