Почему 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# вы почти никогда не увидите таких вещей, как определение операторов для потоковых операций и тому подобное.