C # Нет доступного метода расширения для переопределения с определенным типом - PullRequest
0 голосов
/ 13 сентября 2018

Простите, если об этом уже спрашивали.Я искал его, но ничего не смог найти.

Похоже, что компилятор запутался в этом коде

public abstract class C1
{
    public int c1Prop;
}

public class C2 : C1
{
    public int c2Prop;
}

public abstract class P1
{
    public abstract void Run<T>(T c) where T : C1;
}

public class P2 : P1
{
    public override void Run<C2>(C2 c) 
    {
        c.c1Prop = 1; //Is recognized
        c.c2Prop = 2; //Is NOT recognized and is an error
    }
}

Я не понимаю, почему это не сработает нафункциональный уровень.Поскольку C2 расширяет C1, он не нарушает проверку where, но тип C2 по-прежнему не распознается в переопределенном методе.

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

Еще один потенциальный обходной путь, с которым я столкнулся, - это избавиться от универсального метода все вместе в пользу приведения.Это не кажется таким выразительным, как общий.Кроме того, приведение c в нескольких местах по всему методу Run может раздражать.

Ответы [ 4 ]

0 голосов
/ 13 сентября 2018

Хотя я поддерживаю подход @ DavidG, если вы не хотите использовать обобщенное объявление для своего класса, вы можете использовать этот подход

public interface IC1
{
    int prop1 { get; set; }
}

public interface IC2
{
    int prop2 { get; set; }
}

public abstract class C1 : IC1
{
    #region Implementation of IC1

    public int prop1 { get; set; }

    #endregion
}

public class C2 : C1, IC2
{
    #region Implementation of IC2

    public int prop2 { get; set; }

    #endregion
}

public abstract class P1
{
    public abstract void Run<T>(T c) where T : IC1, IC2;
}

public class P2 : P1
{
    public override void Run<T>(T c)
    {
        c.prop1 = 1; 
        c.prop2 = 2; 
    }
}
0 голосов
/ 13 сентября 2018

Первоначальной причиной путаницы является то, что в вашем Run переопределении C2 является параметром типа - это не класс, называемый C2. Полезно прояснить это, оставив его как T в объявлении переопределяющего метода:

public class P2 : P1
{
    // Changed type parameter name from C2 to T for clarity
    public override void Run<T>(T c) 
    {
        c.c1Prop = 1;
        c.c2Prop = 2;
    }
}

Это абсолютно эквивалентный код, но яснее, что происходит.

Теперь T ограничен where T : C1, как работает c.c1Prop, но вполне возможно 1018 *, что c не будет C2. Например, я мог бы написать:

class OtherC1 : C1 {}

P2 p2 = new P2();
p2.Run(new OtherC1());

Это явно не может работать с вашим текущим кодом - нет c2Prop в OtherC1.

Звучит так, как будто вы хотите, чтобы P1 был универсальным, а не Run методом. Вы могли бы иметь:

public abstract class P1<T> where T : C1
{
    public abstract void Run(T c);
}

public class P2 : P1<C2>
{
    public override void Run(C2 c) 
    {
        c.c1Prop = 1; //Is recognized
        c.c2Prop = 2; //Is NOT recognized and is an error
    }
}

Это будет скомпилировано, и весь код будет знать, что вы можете только предоставить C2 (или более производный класс) для P2.Run. Так что наш предыдущий пример с OtherC1 больше не будет компилироваться (именно этого мы и хотели бы).

0 голосов
/ 13 сентября 2018

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

    public class P2 : P1
    {
        public override void Run<T>(T c)
        {
            c.c1Prop = 1; //Is recognized since you have where T : C1 clause
            var c2 = c as C2;
            if (c2 != null)
            {
                c2.c2Prop = 2;
            }
        }
    }
0 голосов
/ 13 сентября 2018

Когда вы говорите void Run<C2>(C2 c), вы говорите, что C2 - это универсальный тип , это , а не конкретный тип C2. Чтобы сделать это более понятным, измените C2 на T:

public override void Run<T>(T c)
{
    c.c1Prop = 1; //Is recognized
    c.c2Prop = 2; //Is NOT recognized and is an error
}

Причиной, по которой вы можете получить доступ к c1Prop, является ограничение типа where T : C1 ранее в иерархии.

Одним из способов решения этой проблемы было бы сделать P1 общим:

public abstract class P1<T> where T : C1
{
    public abstract void Run(T c);
}

Что делает P2 похожим на это:

public class P2 : P1<C2>
{
    public override void Run(C2 c)
    {
        c.c1Prop = 1;
        c.c2Prop = 2;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...