Как можно приводить между типами без необходимости сначала создавать экземпляр целевого класса? - PullRequest
0 голосов
/ 14 октября 2011

Мне было интересно следующее:

private void RandomEventHandler_Click(object sender, EventArgs e)
{
// SOME CODE IN EVENTHANDLER HERE
}

Button BtnPushed = (Button)sender;

Как получается, что можно преобразовать объект из обработчика событий, например, в Button, но без необходимости сначала создавать объект класса Button?

Например, вот так:

private void RandomEventHandler_Click(object sender, EventArgs e)
{
// SOME CODE IN EVENTHANDLER HERE
}

Button BtnPushed = new Button();

BtnPushed = (Button)sender;

Обычно вам нужно создать объект класса, который является ссылочным типом, прежде чем вы сможете работать с ним.

Пожалуйста, объясните. Спасибо!

Ответы [ 3 ]

2 голосов
/ 14 октября 2011

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

Вместо этого вы можете подумать о обработчике событий

protected void saveButton_Click(object sender, EventArgs e)
{
     Button saveButton = (Button)sender;
}

Это не то же самое, что ваш фрагмент.Вы не создали sender, оно было передано вам.Это было передано как объект.С помощью кода вы утверждаете, что знаете, что во время выполнения sender является действительно кнопкой.Вы говорите компилятору разрешить вам обращаться с ним как с единым целым, и компилятор позволит вам.

Если окажется, что вы не правы , вы столкнетесь с тем жеисключение времени выполнения, упомянутое выше.

Другими словами.Скажем, у вас есть этот фрагмент.

string foo = "FOO";
object obj = foo; 
string bar = (string)obj;
Button baz = (Button)obj;

Все это разрешено во время компиляции.Линия 4 взорвется во время выполнения.Вы создаете строку, вы создаете переменную, которая ссылается на строку как объект, вы создаете другую переменную, где вы приводите ссылку на объект к строке, и четвертую строку вы пытаетесь привести к Button.Строка 2 работает, потому что вы можете рассматривать любой класс или структуру как объект.Строка 3 работает, потому что объект является строкой.Строка 4, очевидно, не будет работать, "FOO" не является кнопкой.

Button button = new Button();
object sender = button;
Button button2 = (Button)sender; 

Естественно, это работает.sender - это кнопка.Теперь свяжите это с моделью события.Обработчик ожидает получить объект через параметр.Вызов обработчика - , на самом деле отправка Button.Как разработчик, вы это знаете, поэтому вы указываете компилятору (через приведение) вместо этого обрабатывать объект как кнопку.

0 голосов
/ 14 октября 2011

Я думаю, вы можете все перепутать.Из приведенных вами примеров я полагаю, что вас могут сбить с толку обработчики событий и тот факт, что они обычно имеют сигнатуру метода вдоль строк void Handler(object sender, EventArgs args), где отправитель может быть экземпляром, скажем, Button.

В ООП типы могут наследоваться от других типов, и вы можете использовать экземпляры унаследованных типов в качестве экземпляров базовых типов, эта концепция называется Полиморфизм .Например, класс Button наследуется от Object, где-то вверх по цепочке наследования.Можно сказать, что унаследованный тип - это специализированный тип его базового типа:

class Person { } // Person is our base type
class John : Person {} // John is a specialized kind of Person

Таким образом, вы можете сказать, что при создании экземпляра Джона это также является экземпляромЧеловек:

John john = new John();
Person johnAsPerson = john; // Perfectly fine, makes sense even

Но не наоборот, потому что не все люди John, некоторые могут быть Steve или Mary, некоторые даже могут быть Person:

Person person = new Person();
John john = person; // Won't work 

В тех случаях, когда мы знаем , что это экземпляр John, мы можем сказать компилятору «не волнуйтесь, я знаю, что я делаю», и явно приведемот Person до John:

Foo(new John());

static void Foo(Person person) {
    John john = (John)person; // We expect it to always be a instance of John
    // If not, the runtime will throw an exception, that we're trying to do an invalid cast
}

Чтобы было ясно, важно различать тип экземпляра и тип переменной:

string a = "123";
//     |    |-> I'm an instance of the Type `string`
//     |-> I'm a variable of type `string`, that points to an instance of type `string`
object o = a;
//     |-> I'm a variable of type `object`, that points to an instance of type `string`

Смысл с обработчиками событий заключается в том, что они обычно предоставляют отправляющий экземпляр элемента управления в форме его базового типа Object.Экземпляр элемента управления все еще очень похож на Button, но мы просто рассматриваем его как Object.Для этого вы можете разыграть Object до Button.

0 голосов
/ 14 октября 2011

Ваш пример не сработает.Исходя из имени отправителя, я предполагаю, что это внутри обработчика событий, который, хотя и передает объект, на самом деле является объектом другого типа, а не Object, как вы написали.

Поэтому, учитывая, что приведение sender к его фактическому типу работает должным образом, потому что объект был того типа с самого начала.

...