“Ограничения для явной интерфейсной реализации …”

У вас есть таблица для хранения основных данных свойства (в этой таблице вы добавляете к ней дополнительные поля по мере необходимости, пока я не получу окончательный дизайн таблицы) Пример: main_property_file (property_id PK, address, GPS_location) Затем вам нужно знать, что это это для аренды или продажи, справочная таблица сборки содержит это, например: property_for (typefor PK, назовите это). И собираюсь добавить файл в предыдущем файле main_property_file для typefor, поданный как внешний ключ. И так далее, пока вы не поместите всю структуру бизнес-данных, затем чтобы проверить таблицы и отношения на предмет согласованности, вы можете поместить это в визуальный инструмент, если не можете представить связь и данные, которые хранятся в каждой таблице, и, наконец, попросить вашу модель с запросом найти информацию или ввести новые данные и так далее, чтобы убедиться, что Разработка таблицы завершена, и пересмотрите ограничения .

5
задан vdhant 13 November 2008 в 03:25
поделиться

8 ответов

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

Я не могу сказать, что полностью понимаю Вашу мотивацию, но она имеет техническую заслугу.

Моя первая попытка использовала базовый класс, имеющий Невиртуальный открытый интерфейс и затем защищающий другого виртуальный метод CheckCreatedType это позволило бы чему-либо в цепочке осматривать тип, прежде чем базовый класс Создаст, был назван.

public class A
{
    public IFieldSimpleItem Create()
    {
        IFieldSimpleItem created = InternalCreate();
        CheckCreatedType(created);
        return created;
    }

    protected virtual IFieldSimpleItem InternalCreate()
    {
        return new SimpleImpl();
    }
    protected virtual void CheckCreatedType(IFieldSimpleItem item)
    { 
        // base class doesn't care. compiler guarantees IFieldSimpleItem
    }
}
public class B : A
{
    protected override IFieldSimpleItem InternalCreate()
    {
        // does not call base class.
        return new NormalImpl();
    }
    protected override void CheckCreatedType(IFieldSimpleItem item)
    {
        base.CheckCreatedType(item);
        if (!(item is IFieldNormalItem))
            throw new Exception("I need a normal item.");

    }
}

Следующее всовывает проверку времени выполнения в базовом классе. Неразрешимая проблема - Вы, все еще должны полагаться на называемый метод базового класса. Неправильно себя ведущий подкласс может повредиться, все проверяет не вызов base.CheckCreatedType(item).

Альтернативы - Вы hardcode все проверки на все подклассы в базовом классе (плохо) или иначе воплощают проверку.

Попытка 2: Классы (Sub) регистрируют проверки, в которых они нуждаются.

public class A
{
    public IFieldSimpleItem Create()
    {
        IFieldSimpleItem created = InternalCreate();
        CheckCreatedType(created);
        return created;
    }

    protected virtual IFieldSimpleItem InternalCreate()
    {
        return new SimpleImpl();
    }

    private void CheckCreatedType(IFieldSimpleItem item)
    {
        Type inspect = this.GetType();
        bool keepgoing = true;
        while (keepgoing)
        {
            string name = inspect.FullName;
            if (CheckDelegateMethods.ContainsKey(name))
            {
                var checkDelegate = CheckDelegateMethods[name];
                if (!checkDelegate(item))
                    throw new Exception("failed check");
            }
            if (inspect == typeof(A))
            {
                keepgoing = false;
            }
            else
            {
                inspect = inspect.BaseType;
            }
        }
    }

    private static Dictionary<string,Func<IFieldSimpleItem,bool>> CheckDelegateMethods = new Dictionary<string,Func<IFieldSimpleItem,bool>>();
    protected static void RegisterCheckOnType(string name, Func<IFieldSimpleItem,bool> checkMethod )
    {
        CheckDelegateMethods.Add(name, checkMethod);
    }
}
public class B : A
{
    static B()
    {
        RegisterCheckOnType(typeof(B).FullName, o => o is IFieldNormalItem);
    }

    protected override IFieldSimpleItem InternalCreate()
    {
        // does not call base class.
        return new NormalImpl();
    }
}

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

Я предполагаю, что это - ошибка разработчика, которую Вы пытаетесь зафиксировать. Если это применимо, можно украсить метод проверки на этапе выполнения System.Diagnostics.Conditional("DEBUG")], разрешение Версии выпуска пропустить проверки.

Мое знание дженериков не прекрасно, поэтому возможно, это является ненужным. Однако проверки здесь не должны быть для одного только типа: это могло быть адаптировано к другому использованию. например, делегат передал в Register.. не должен просто проверять, что ссылка является определенным типом'

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

3
ответ дан 14 December 2019 в 04:50
поделиться

Это не позволяется, потому что это нарушает принцип замены Лисков.

Скажем, у Вас есть другой интерфейс:

public interface IFieldSuperItem : IFieldSimpleItem

Вы затем могли бы сделать это

Person p = new Boss();
p.Create<IFieldSuperItem>();

Вызов во второй строке, в то время как совместимый с определением Создают лично, но очевидно не совместимые с определенным в Боссе (которые только работают с IFieldNormalItem и его подклассом).

2
ответ дан 14 December 2019 в 04:50
поделиться

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

public class Bose : Person
{
    public virtual T CreateNormal<T>()
        where T : IFieldNormalItem //This is where the error is
    {
        return default(T);
    } 
}

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

1
ответ дан 14 December 2019 в 04:50
поделиться

Изменение универсального ограничения изменяет сигнатуру метода, которая не позволяется, если Вы переопределяете виртуальное.

Я думаю, что Вы, возможно, должны разделить Создать метод на отдельный класс:

public interface IFieldSimpleItem { }

public interface IFieldNormalItem : IFieldSimpleItem{ }

public interface IFieldCreator<TField, TPerson> where TField : IFieldSimpleItem where TPerson : Person
{
    TField Create(TPerson person);
}

public class Person
{
}

public class Bose : Person
{
}

public class PersonFieldCreator : IFieldCreator<IFieldSimpleItem, Person> 
{
    public IFieldSimpleItem Create(Person person) { return null; }
}

public class BoseFieldCreator : IFieldCreator<IFieldNormalItem, Bose>
{
    public IFieldNormalItem Create(Bose person) { return null; }
}
1
ответ дан 14 December 2019 в 04:50
поделиться

Самый простой пример - то, что это повреждает полиморфизм. Если бы у Вас был набор Человека, где один или несколько из тех объектов имеет тип Bose, это отказало бы, как только это поражает Bose.

Person[] people;
[...initialize this somewhere...]

foreach(Person p in people)
  p.Create<IFieldSimpleItem>();
0
ответ дан 14 December 2019 в 04:50
поделиться

Кажется, что Вы не можете изменить определение метода, но можно ли сделать классы универсальными вместо Создать Метода?

public class Person<T> where T : IFieldSimpleItem
{
    public virtual T Create()
    {
        return default(T);
    }
}

public class Bose<T> : Person<T> where T : IFieldNormalItem
{
    public override T Create()
    {
        return default(T);
    } 
}
1
ответ дан 14 December 2019 в 04:50
поделиться

Что относительно этого:

public interface IFieldNormalItem : IFieldSimpleItem
{ }

public class Person<T> where T : IFieldSimpleItem
{
    public virtual T Create()
    {
        return default(T);
    }
}

Теперь Вы можете иметь Person<IFieldSimpleItem> (соответствует Person) или Person<IFieldNormalItem> (соответствует Bose).

0
ответ дан 14 December 2019 в 04:50
поделиться

Кода ниже достаточно для переопределения. Тип T уже обозначается как потребность, которая будет реализована IFieldSimpleItem в Человеке базового класса.

public class Bose : Person
{
    public override T Create<T>()
        // where T : IFieldNormalItem // You don't need this line.
    {
        return default(T);
    } 
}

РЕДАКТИРОВАНИЕ: Я полностью понял вопрос превратно, таким образом, код выше не решит этот случай. Единственная вещь, которую необходимо сделать; не переопределять Создать метод "переопределением", но "виртуальный".

public class Bose : Person
{
    public virtual T Create<T>()
        where T : IFieldNormalItem
    {
        return default(T);
    } 
}
0
ответ дан 14 December 2019 в 04:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: