2

Я был удивлен, увидев сегодня, что это возможно, но я беспокоюсь, что это должно обсуждаться раньше.Почему C# дразнят со структурной типизацией, когда он абсолютно знает, что у нее ее нет?

public interface ICanAdd 
{ 
    int Add(int x, int y); 
} 

// Note that MyAdder does NOT implement ICanAdd, 
// but it does define an Add method like the one in ICanAdd: 
public class MyAdder 
{ 
    public int Add(int x, int y) 
    { 
     return x + y; 
    } 
} 

public class Program 
{ 
    void Main() 
    { 
     var myAdder = new MyAdder(); 
     var iCanAdd = (ICanAdd)myAdder; //compiles, but for what sake? 
     int sum = iCanAdd.Add(2, 2); //na, not game for it, cast had already failed 
    } 
} 

Компилятор (правильно?) Скажет мне, что в приведенной выше ситуации существует явное литье. Я был взволнован, чувствуя структурную типизацию там, но времени на запуск не удается. Итак, когда C# всегда помогает? Любые сценарии такого кастинга будут работать? Как бы то ни было, я уверен, что компилятор заранее знает, myAdder не ICanAdd, ну технически.

+2

Почему нисходящий? Есть ли у меня еще один сеанс мозгового пердеть? – nawfal

+0

Хороший вопрос! Где «сумматор» в 'adder.Add' определен? Вы имели в виду 'iCanAdd'? – dasblinkenlight

+0

@ dasblinkenlight да конечно. Я отредактирую опечатку :) Но в любом случае эта строка не попадает. – nawfal

ответ

9

C# позволяет явное преобразование из класса в интерфейс (даже если класс не реализует этот интерфейс), поскольку для всего компилятора известно, что ссылка на определенный тип может быть действительно (неопределенность в том, что это явное, а не неявное преобразование), является экземпляром производного типа, который делает реализовать интерфейс. Расширение вашего примера, предположим, что у вас есть:

public class DerivedAdder : MyAdder, ICanAdd 
{ 
    int ICanAdd.Add(int x, int y) 
    { 
    return base.Add(x, y); 
    } 
} 

... 

MyAdder myAdder = new DerivedAdder(); 
var iCanAdd = (ICanAdd)myAdder; // Valid in this case 
int sum = iCanAdd.Add(2, 2); // sum = 4 

Если вы проверяете раздел 6.2.4 в C# Specification, вы увидите, что если вы отмечаете свой MyAdder класс как sealed, компилятор на самом деле жалуются, потому что тогда это будет точно не знаю, что никакое преобразование невозможно, так как никакой производный тип не может существовать. Но до тех пор, пока он не сможет устранить все последние сомнения, он позволит явное преобразование.

+0

Я обновил ваш ответ от чего-то из ваших комментариев, что ясно для меня. Надеюсь, все в порядке. – nawfal

1

Класс отливки для интерфейса допускается C# language specification. Но, например, если ICanAdd был классом - компиляция завершилась неудачно