Вот классы и интерфейсы у меня есть:C#: Почему мы должны явно применять класс к интерфейсу для доступа к недвусмысленным реализованным методам класса?
public interface Baz {
void someMethod();
}
public interface Foo {
void someMethod();
}
public class Bar : Foo {
void Foo.someMethod(){}
}
Вопрос 1) Можно ли удалить интерфейс Foo из объекта Bar, или добавить интерфейс База к объекту Bar во время выполнения возможного?
Если да, могу ли я получить образец короткого кода о том, как это делается?
Если нет, пожалуйста, переходите к вопросу 2 и 3.
Вопрос 2) Почему C# не дает ошибку компиляции при заливке объекта к интерфейсу, он не реализует? Если вы ответите на вопрос 1, нет, mybar никогда не будет Baz, так почему же ошибка компилятора?
void myFunction(){
Bar mybar = new Bar();
(mybar as Baz).someMethod();
}
Вопрос 3) Почему не C# позволяет мне позвонить SomeMethod из объекта Бар без приведения к Foo, даже если он знает, что SomeMethod не является неоднозначным?
void myFunction(){
Bar mybar = new Bar();
mybar.someMethod();//doesn't work
mybar.Foo.someMethod();//doesn't work (C# could do this and give a compile error if Bar has a property or public variable with the same name as an interface that it implements to allow for this syntax)
(mybar as Foo).someMethod();//works even though someMethod is not ambiguous.
//The problem with this is that the keyword "as" has an option to return null, which I want to be very assured will never be the case.
}
Технически, компилятор может быть более полезным в обоих случаях, к примеру, так как он знает точный тип mybar, как и в 2, это может привести к ошибке в вызове someMethod, недоступном для кода. Если mybar пришел как параметр, компилятор не знал бы, что mybar является фактическим объектом «Bar», а не «SuperBar», который расширяет как «Bar», так и «Baz».В примере 3, то же самое, он может разрешить вызов someMethod, поскольку он _knows_ точный тип mybar, однако, если он пришел как параметр, вы не знали бы, что объект не также расширяет Baz, делая вызов неоднозначным. –
Сделать более удобным сделать вызов в примере 3 будет особый случай, который очень ограничен, но требует изменения кода для всех случаев, за исключением случаев, когда объект во время компиляции оказывается определенным типом, и, вероятно, сбивает с толку, когда доказательство не может быть выполнено, и компилятор потребует изменения кода для компиляции кода. –
Обратите внимание, что в сценарии, указанном в части 2, это ошибка, если Bar является закрытым классом или структурой. Я подозреваю, что компилятор мог быть написан, чтобы дать ошибку в чрезвычайно простом сценарии, но стоимость считалась запретительной, если сценарий был более сложным (дополнительные переменные, вызовы методов и т. Д.). Поэтому, вместо того, чтобы сделать его сложным или непоследовательным (в зависимости от того, вызываются ли локальные переменные или методы), авторы компилятора выбрали поведение с простым правилом: проверьте преобразование, если тип является типом значения или закрытым классом, и не проверьте в противном случае. –