Листинг объекта в С# всегда возвращает ссылку на исходный объект

В настоящее время я делаю проект на С#, работающем с формами окон. В ходе этого я сделал следующее

        void HideButtons(object sender, EventArgs e)
    {
        Button hider = ((Button)sender);
        foreach(Button tohide in hider.Parent.Controls)
            tohide.Hide();
        hider.Show();
        hider.Text = "UnHide";
        hider.Click -= new EventHandler(HideButtons);
        hider.Click += new EventHandler(ShowButtons); 
    }

Цель этого кода - иметь кнопку, которая скрывает все остальные кнопки в контейнере за исключением самого себя, а затем превращается в кнопку Unhide, которая делает то же самое в обратном порядке.

Теперь, это все хорошо и хорошо, за исключением того, что, компилируя это, я понимаю, что у меня проблема. hider - его уникальный объект, являющийся возвратом из ((Button) отправителя). Это не обязательно ссылка на отправителя, и этот код, вероятно, ничего не сделает.

Но низко, и вот, он работает точно так, как я хотел, и изначально думал, что это будет. Что заставило меня задаться вопросом, делает ли бросок всегда возвратом ссылки на исходный объект? Если нет, как я могу гарантировать, что (кнопка) отправитель = отправитель?

Я знаю, что не для удвоений /ints, так как

        public static int Main()
    {
        int a;
        double b;
        b = 10.5;
        a = (int)b;
        a++;
        return 0;
    }

заканчивается существом 11, а b - 10.5. Но это может быть связано с тем, что структуры double/ints являются структурами. Такое поведение меня беспокоит, и было бы хорошо знать, что он всегда будет возвращать ссылку, чтобы я мог успокоить мой беспокойный ум.

Ответ 1

Для ссылочных типов. если бросок просто вверх или вниз по иерархии наследования, то да. Это ссылочное преобразование. Из спецификации языка С# 3.0, раздел 6.2.4:

Преобразования ссылок, неявные или явно, никогда не меняют ссылочный идентичность объекта, являющегося преобразованный. Другими словами, хотя ссылочное преобразование может изменить тип ссылки, он никогда изменяет тип или значение объект, на который ссылается.

Это тот случай, который вы используете в своем коде WinForms.

Однако в других (все еще ссылочных типах) случаях он может вызывать пользовательское преобразование. Например:

using System;

class Foo
{
}

class Bar
{
    public static explicit operator Bar(Foo f)
    {
        return new Bar();
    }
}

class Test
{
    static void Main()
    {
        Foo f = new Foo();
        Bar b = (Bar) f;
        Console.WriteLine(object.ReferenceEquals(f, b)); // Prints False
    }
}

Пользовательские преобразования, подобные этому, относительно редки.

Для типов значений существуют преобразования бокса и распаковки вместе с другими преобразованиями (например, между int и double).

Ответ 2

Для ссылочных типов, вытесненных иерархией наследования, он всегда ссылается на один и тот же экземпляр. Однако для типов значений приведения могут включать бокс и распаковку, которые будут копировать материал. Помимо этого, приведения не только в иерархии наследования. Вы можете объявить свой собственный оператор литья, который имеет характеристики метода. Он может вернуть любой объект, который ему нравится.