Почему C# не поддерживает перегрузку операторов с помощью pass by reference?
Является ли это ограничением среды CLR или решением по проектированию языка? Я попытался сделать это в C++/CLI, конечно, где это работает, потому что нужно поддерживать родной c++:
public ref class Test
{
public:
static Test^ operator &( Test^ msg, int& i )
{
i = i + 1;
return nullptr;
}
};
А потом посмотрел на пропущенный компилятором вывод:
public: static Test __gc* op_BitwiseAnd(Test __gc* msg, Int32 __gc** modopt(IsImplicitlyDereferenced __gc*) i)
{
i[0] += 1;
return 0;
}
Я пошел дальше и попытался вызвать этот оператор из проекта C# - и, конечно, мне нужно было пойти [небезопасно], чтобы сделать это( мне нужен был указатель):
Test t = new Test();
int i = 0;
unsafe
{
t = t & &i;
}
Очевидно, не так сложно реализовать для CLR? Мне очень не хватает пропуска по ссылке в операторах перегрузка и хотелось бы хотя бы в свете себя в чем-то упустить?
Почему C# не может скрыть уродство за небезопасными и указателями, когда нам нужно иметь дело с ссылочными переменными в наших перегрузках операторов? Даже если бы я решил пойти с этим уродливым обходным путем, это не сработало бы в Silverlight, где небезопасные операции не разрешены...
2 ответа:
В C# ваши переменные никогда не изменяются вызываемыми без явной передачи их в качестве ссылок (например,
int.TryParse(s, out i)
, где вы явно указываете ключевое словоout
). Эта функция усложняет задачу, позволяя перегруженному оператору изменять содержимое операндов без вашего явного разрешения.Например,
public static MyStruct operator + (ref MyStruct left, ref MyStruct right) { left = new MyStruct(); // !!!!!!!! return something(left, right); }
Когда вы ссылаетесь на такой оператор в C#:
MyStruct x = new MyStruct(); MyStruct y = new MyStruct(); MyStruct z = x + y; // in C#, you never expect `x` to be changed.
Я думаю, что это потому, что оператор (в более математическом представлении, которое, по-видимому, принимает C#) логически является чем-то, что объединяет свои аргументы в новое значение, никогда не предполагая, что что-то мутирует. C++, по-видимому, рассматривает операторы скорее как версию общих операций с более удобным синтаксисом, чем функции, чем как способ представления математики в частности. Я думаю, что в C# вы почти никогда не увидите таких вещей, как определение операторов для потоковых операций и тому подобное.