Ehsan Sajjad Ответов: 2

Почему cast to interface не проверяется во время компиляции в C# ?


Привет,

Я только что видел вопрос, заданный кем-то другим, на который никто не дал ответа staisfacotry, и просто из любопытства я также хотел знать, почему это время компиляции законно, но, конечно, это не сработает во время выполнения, вот код:

public class DummyClassFactory
    {
        public Object GetDummyClassInstance()
        { 
            var dummyClass = new DummyClass();
			
            switch (DateTime.Now.DayOfWeek)
            {
                // Starting on monday.
                case DayOfWeek.Monday:
                    return (IDisposable)dummyClass;
                
               
                case DayOfWeek.Thursday:
                    return (IServiceProvider)dummyClass;
                case DayOfWeek.Friday:
                    return (IEquatable<List<Single>>)dummyClass;
                case DayOfWeek.Saturday:
                    return (IFormattable)dummyClass;
                
            }
            // return (DummyClassFactory)dummyClass; 
            return dummyClass;
        }
    }

    public class DummyClass { }
    public interface IDummyClass { }


Может ли кто - нибудь пролить свет, почему это так?

Вот демонстрационная скрипка : .Объем демо-Скрипка[^]

Спасибо,
Эхсан Саджад

Что я уже пробовал:

public class DummyClassFactory
    {
        public Object GetDummyClassInstance()
        { 
            var dummyClass = new DummyClass();
			
            switch (DateTime.Now.DayOfWeek)
            {
                // Starting on monday.
                case DayOfWeek.Monday:
                    return (IDisposable)dummyClass;
                
               
                case DayOfWeek.Thursday:
                    return (IServiceProvider)dummyClass;
                case DayOfWeek.Friday:
                    return (IEquatable<List<Single>>)dummyClass;
                case DayOfWeek.Saturday:
                    return (IFormattable)dummyClass;
                
            }
            // return (DummyClassFactory)dummyClass; 
            return dummyClass;
        }
    }

    public class DummyClass { }
    public interface IDummyClass { }

Graeme_Grant

Это лучше объяснит то, что вы видите: Разница между ранним и поздним связыванием[^]

2 Ответов

Рейтинг:
9

Wendelius

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

Все резко изменится, если вы запечатаете класс:

public sealed class DummyClass { }


Рейтинг:
20

OriginalGriff

Это немного сложно,но я постараюсь объяснить...

Помните, что класс может быть производным от одного базового класса (конкретного или абстрактного), но также может наследовать несколько интерфейсов. Таким образом, классы-потомки могут реализовывать интерфейсы, которых не было у исходного базового класса.

class MyBase{}
class MyDerived : MyBase {}
class MyOtherDerived : MyDerived, IInterface1, IInterface2 {}

Поскольку переменная типа MyBase может содержать любой тип объекта на основе MyBase, она может предположительно содержать экземпляр класса MyOtherDerived, который поддерживает два интерфейса, поэтому его можно привести к любому из них (с соответствующими проверками во время выполнения, чтобы убедиться, что он работает).
Это все достаточно просто, и вы могли бы сказать: "ни один производный класс не реализует IDontKnowWhatToCallIt, поэтому вы не должны быть в состоянии привести к нему, и вы должны получить ошибку компилятора".

Но... система этого не знает. Вполне возможно, что совершенно другая сборка действительно создает класс, производный от MyBase, и который реализует интерфейс IDontKnowWhatToCallIt - поэтому он не может создать ошибку времени компиляции, не серьезно испортив ваш код!

Если ваш базовый класс sealed он может проверить - и он это делает, и вызовет ошибку компилятора. Но для производных классов он должен ошибаться на "безопасной" стороне и пропускать приведение и полагаться на проверки времени выполнения, чтобы вызвать исключение.


Wendelius

Быстрые у вас пальцы :)

Гораздо больше текста в то же время, как я написал всего несколько строк.

[no name]

Правда.

OriginalGriff

Наследие курса компьютерного набора текста, много-много лет назад! ("Мэвис Бикон учит печатать на машинке", еще во времена DOS!)

[no name]

Сэр, ответьте на мой вопрос, если у вас есть время.

OriginalGriff

Какой? У вас их 20...

[no name]

Вопрос: Join возвращает четыре строки вместо двух.

OriginalGriff

У меня не установлен MySql, поэтому я не могу протестировать какое - либо решение-мне придется оставить его другим!

Wendelius

До сих пор не понимаю, почему так быстро.

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

В моем случае prefetch означает, что два пальца пишут и восемь пальцев ищут следующий символ... :)

OriginalGriff

Мои пальцы закодированы вручную на ассемблере!