Не можете прочитать свойство интерфейса из подкласса, который его реализует? - PullRequest
0 голосов
/ 06 мая 2020

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

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

Это лучше объяснить с помощью примера ( NetFiddle ) и вопросов ...

using System;

public interface IAb
{
    int Prop1 { get; set; }
}

public class A : IAb
{
    public int Prop1 { get; set; }
}

public class B : A, IAb
{
    public string Prop2 { get; set; }
}

public class Program
{
    static class MyMethods
    {
        public static IAb CreateObject(Type t)
        {
            if (t == typeof(A))
            {
                return new A() {Prop1 = 123};
            }
            else
            {
                return new B() {Prop1 = 456, Prop2 = "Foo"};
            }
        }
    }

    public void Main()
    {

        IAb AorB = MyMethods.CreateObject(typeof(B));
        Console.WriteLine(AorB.Prop1);

        if (AorB is B)
        {

            // fails
            // Console.WriteLine((B)AorB.Prop2); // 'IAb' does not contain a definition for 'Prop2'

            // works
            B newVar = (B)AorB;
            Console.WriteLine(newVar.Prop2);

        }
    }
}

На основании вышеизложенного:

  1. Почему AorB.Prop1 работает, но не AorB.Prop2 без явного приведения?
  2. Означает ли вышесказанное, что интерфейс всегда должен быть приведен к класс перед чтением его свойств?
  3. Есть ли лучший способ указать тип возвращаемого значения для примера метода? Текущий подход кажется подверженным ошибкам, потому что этот (хотя и маловероятный код) вызовет ошибку: var AorB = (B) MyMethods.CreateObject(typeof(A));

Ответы [ 2 ]

2 голосов
/ 06 мая 2020

Почему AorB.Prop1 работает, но не AorB.Prop2 без явного приведения?

Потому что селектор свойств имеет приоритет над приведением типа. Просто добавьте круглые скобки:

Console.WriteLine(((B)AorB).Prop2);

Означает ли вышесказанное, что интерфейс всегда должен быть приведен к классу перед чтением его свойств?

Нет.

Есть ли лучший способ указать возвращаемый тип метода примера? Текущий подход кажется подверженным ошибкам, потому что этот (хотя и маловероятный код) вызовет ошибку: var AorB = (B) MyMethods.CreateObject (typeof (A));

Вы можете использовать дженерики:

T CreateObject<T>() where T : new()
{
    return new T();
}

Однако это не дает вам доступа во время компиляции к свойствам, как в вашем примере. Вы можете немного улучшить, предоставив версии метода с соответствующими ограничениями:

T CreateObject<T>() where T : IAb, new()
{
    var result = new T();
    result.Prop1 = 123;
    return result;
}
2 голосов
/ 06 мая 2020

Вы можете использовать сопоставление с шаблоном с оператором is, чтобы сделать его более понятным

IAb AorB = MyMethods.CreateObject(typeof(B));
Console.WriteLine(AorB.Prop1);
if (AorB is B b)
{
    Console.WriteLine(b.Prop2);
}

Ваша неудачная строка становится правильной после использования правой круглой скобки

Console.WriteLine(((B)AorB).Prop2);

Также нет необходимости наследовать класс B как от класса A, так и от интерфейса IAB. Поскольку A уже реализует IAB, вы можете просто использовать public class B : A

Есть ли лучший способ указать тип возвращаемого значения для примера метода?

Сделайте метод CreateObject generi c и используйте ограничения для ограничения параметра типа T классом, который реализует интерфейс IAb и имеет конструктор без параметров (именно это new() означает именно)

public static T CreateObject<T>() where T : IAb, new()
{
    return new T { Prop1 = 123 };
}

и вызвать его следующим образом:

IAb AorB = MyMethods.CreateObject<B>();

Но в этом случае вы можете установить только свойства, определенные в интерфейсе IAb, а не B класс, указанный c.

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