Почему GetType () класса, «разрезанного» по интерфейсу, говорит мне, что это не тот класс? - PullRequest
0 голосов
/ 28 февраля 2019

Вот мой код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            ISampleInterface a = new A();
            ISampleInterface b = new B();

            a.SampleMethod();
            b.SampleMethod();

            //Console.WriteLine(a.myValue); // can't do it!! a is not A
            Console.WriteLine(a.GetType()); // uhm...
        }
    }

    interface ISampleInterface
    {
        void SampleMethod();
    }

    class A : ISampleInterface
    {
        public double myValue = 10.0;

        public void SampleMethod() {
            Console.WriteLine("A");
        }
    }

    class B : ISampleInterface
    {
        public double myValue = 20.0;

        public void SampleMethod() {
            Console.WriteLine("B");
        }
    }
}

Я запускаю класс по интерфейсу (реализуется классом).

Очевидно, что не могу получить доступ к a.myValue, потому что правильно Rextester.ISampleInterface не содержит такого определения.

Но если я спрашиваю компилятор, какой тип a, он выдает Rextester.A (что, я считаю, не является).

Почему?И что более важно, какой класс a?Что-то вроде гибридного класса, ограниченного интерфейсом?Не уверен, как бы я это определил ...

Ответы [ 3 ]

0 голосов
/ 28 февраля 2019

a.myValue недоступен, так как находится в области видимости, так как ISampleInterface

a.GetType() правильно приводит к A, потому что это разрешается во время выполнения экземпляру типа, назначенного a,что A.Он находится только в области видимости ISampleInterface.

Например ...

ISampleInterface a = new A();

Вы создаете экземпляр из A, объявленный как ISampleInterface.

a.SampleMethod();

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

Console.WriteLine(a.myValue);

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

Console.WriteLine(a.GetType());

GetType вызывается из System.Object, который естественным образом расширяется, так что вы можете вызвать его, потому что он объявлен неявным базовым типом.В этом контексте GetType возвращает A, потому что это именно то, что a;экземпляр A.

0 голосов
/ 28 февраля 2019

Но если я спрашиваю компилятор, какой тип a, он выводит Rextester.A (что, я полагаю, не *)

Если под "запросом компилятора" вы имеете в видузвоните a.GetType(), это не то, что вы делаете.Вы запрашиваете время выполнения для фактического типа объекта, на который a ссылается.Среда выполнения правильно сообщает вам, что это Rextester.A.

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

Если вы приведете к переменной A, то вы сможете получить доступ к ее членам:

A newA = a;
newA.myValue = 15;  // perfectly valid

Обратите внимание, что фактический объектa ссылается не изменилось (это означает, что это тот же объект - очевидно, вы изменили одно из его полей-членов).Вы по-прежнему можете ссылаться на интерфейс через a или через класс newA.

Если вы спросили компилятор, что это за тип a, но с использованием метода, подобного этому:

public Type GetCompileTimeType<T>(T inputObject)
{
    return typeof(T);
}

(кредит этот ответ )

и звонок

Console.WriteLine(GetCompileTimeType(a));

, вы получите Rextester.ISampleInterface

0 голосов
/ 28 февраля 2019

Какие методы вы можете вызывать (вне отражения / dynamic), основаны на типе времени компиляции переменной .

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

Нет ничего сравнимого с нарезкой в ​​C ++ (на что, я полагаю, вы ссылаетесь, нарезая) вМир .NET, о котором я могу подумать - конечно, вы не получите его от написания простого кода.

Переменная, объявленная как тип интерфейса, никогда не будет содержать ссылку на что-то "просто"этот интерфейс.Это всегда будет объект определенного конкретного типа структуры / класса.

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