Почему 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 5

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