powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / c# не соответствие классов с интерфейсом
25 сообщений из 29, страница 1 из 2
c# не соответствие классов с интерфейсом
    #39901917
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго дня! Уважаемые форумчане)

Подскажите пожалуйста, реально ли каким-то образом заставить ниже приведённый код работать? Или в шарпе настолько строгая типизация, что даже наследованный интерфейс классом, не преобразуется в шарпе.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
using System;
using System.Linq.Expressions;

namespace Test
{
    public interface IBase { int Id { get; set; } }
    public class Run
    {
        public Run()
        {
            Expression<Func<IBase, bool>> filter = x => x.Id == 1;
            var a1 = new A1(filter);
        }
    }

    public class A1 : AbstrReload<Entity1>
    {
        public A1(Expression<Func<IBase, bool>> filter)
        {
            Reload(filter); // Вот здесь происходит не соответствие типов
        }
    }

    public abstract class AbstrReload<TEntity>
        where TEntity : class, IBase
    {
        protected void Reload(Expression<Func<TEntity, bool>> filter)
        {
        } 
    }

    public class Entity1 : IBase
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class Entity2 : IBase
    {
        public int Id { get; set; }
        public string Caption { get; set; }
    }
}
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39901922
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
читай про ковариантность и контравариантность
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39901945
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro,
Прочитал

Но в данном случае нужно использовать джинерик интерфеёсы, а я то использую простой интерфейс. Как быть тогда?
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39902004
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Expression инвариантен.
Что мешает объявить
Код: c#
1.
protected void Reload(Expression<Func<IBase, bool>> filter)
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39902066
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro
Expression инвариантен.
Что мешает объявить
Код: c#
1.
protected void Reload(Expression<Func<IBase, bool>> filter)



Можете показать как сделать, просто я что-то не догоняю)
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39902068
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А то, что я написал, это не считается, что я показал?
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39902075
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro
А то, что я написал, это не считается, что я показал?


Нет, мне надо чтобы метод Reload использовал TEntity! Для того чтобы я мог в случае необходимости отправить другой интерфейс, к примеру IBaseVisible и др.
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39902079
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Идея реализовать что-то вот это:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
public abstract class AbstrReload<TEntity>
        where TEntity : class, IBase
    {
        protected DbContext Context;

        protected void Reload(Expression<Func<TEntity, bool>> filter)
        {
            List<TEntity> items = Context.Set<TEntity>().AsNoTracking().Where(filter).ToList();
        }
    }


Ну и как вы уже понимаете в фильтр может быть не только интерфейс, но и Entity1 и Entity2
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39902221
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nechto
Shocker.Pro
А то, что я написал, это не считается, что я показал?


Нет, мне надо чтобы метод Reload использовал TEntity! Для того чтобы я мог в случае необходимости отправить другой интерфейс, к примеру IBaseVisible и др.
Ну и в чем проблема?

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
    public abstract class AbstrReload<TEntity>
        where TEntity : class, IBase
    {
        protected void Reload(Expression<Func<IBase, bool>> filter)
        {
        }
    }

    public interface IBaseVisible : IBase { bool Visible { get; set; } }
    public class A2 : AbstrReload<IBaseVisible>
    {
        public A2(Expression<Func<IBase, bool>> filter)
        {
            Reload(filter); 
        }
    }

Вы же ограничили TEntity как IBase, вот с ним и работайте дальше.
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39902226
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Или так:

Код: c#
1.
2.
3.
4.
5.
6.
7.
    public class A1 : AbstrReload<Entity1>
    {
        public A1(Expression<Func<Entity1, bool>> filter)
        {
            Reload(filter);
        }
    }


Но фильтр нужно будет задавать конкретно:

Код: c#
1.
 Expression<Func<Entity1, bool>> filter = x => x.Id == 1;
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903306
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Все варианты решения, которые вы предложили они мне не совсем подходят. Мне нужна универсальность. Чтобы оба варианта работали, а в данном случае работает только первый.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
public interface IBase { int Id { get; set; } }
public class Entity1 : IBase
{
    public int Id { get; set; }
    public string Name { get; set; }
}
public class Entity2 : IBase
{
    public int Id { get; set; }
    public string Caption { get; set; }
}
// Вариант №1
Expression<Func<Entity1, bool>> filter = x => x.Name != null;
new A1(filter);

// Вариант №2 (Ошибка при преобразовании IBase в Entity1 или Entity2)
Expression<Func<IBase, bool>> filter = x => x.Id == 1;
Expression convert = Expression.Convert(filter.Body, typeof(Entity1));




Сам код я его немного доработал:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
public class A1 : AbstrReload<Entity1>
{
    public A1(Expression<Func<Entity1, bool>> filter)
    {
         Reload(filter);
    }
}
public abstract class AbstrReload<TEntity> where TEntity : class, IBase
{
    protected void Reload(Expression<Func<TEntity, bool>> filter)
    {
    } 
}
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903308
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я не понимаю, какая универсальность тебе нужна.
У тебя TEntity ограничен IBase. Всё. Ты не сможешь использовать никакие члены, кроме членов IBase, поэтому метод можно смело делать IBase. Если ты планируешь использовать прямое приведение к типу Entity1 - это пахнет говнокодом. А если собираешься использовать рефлексию, то вообще всё равно, что у тебя там написано.
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903364
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro
Я не понимаю, какая универсальность тебе нужна.
У тебя TEntity ограничен IBase. Всё. Ты не сможешь использовать никакие члены, кроме членов IBase, поэтому метод можно смело делать IBase. Если ты планируешь использовать прямое приведение к типу Entity1 - это пахнет говнокодом. А если собираешься использовать рефлексию, то вообще всё равно, что у тебя там написано.


Почему я не могу привести IBase к Entity1? Это вообще возможно в c#?
Код: c#
1.
2.
Expression<Func<IBase, bool>> filter = x => x.Id == 1;
Expression convert = Expression.Convert(filter.Body, typeof(Entity1));



Ну а если убрать public abstract class AbstrReload<TEntity> where TEntity : class, IBase
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903377
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я уже сказал - пахнет говнокодом. Зачем тебе нужна абстракция IBase, если ты хочешь приводить к конкретным типам? Используй более общую абстракцию тогда, вплоть до object
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903379
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro
Я уже сказал - пахнет говнокодом. Зачем тебе нужна абстракция IBase, если ты хочешь приводить к конкретным типам? Используй более общую абстракцию тогда, вплоть до object


Понять не могу, в чем говнокод? Простое приведение интерфейса к классу.
Объясните пожалуйста
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903382
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если вызывающий класс зависит от вызываемого, а вызываемый класс зависит от вызывающего.
Можно выкинуть все интерфейсы и обобщенные члены, потому что смысл абстракции пропадает.
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903394
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nechto
Понять не могу, в чем говнокод? Простое приведение интерфейса к классу.
Объясните пожалуйста


Чего тут объяснять? Суть интерфейса в сокрытии реализации.
Когда вы приводите интерфейс к классу, смысл в интерфейсе пропадает начисто.
Передавайте всё тупо через ссылку на object тогда и везде приводите к нужному классу.
Посмотрите что ваши коллеги на это скажут ))
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903399
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
по сути, это нарушение принципа Барбары Лисков (SOLID), когда мы абстракцию приводим к её реальному типу.
Если вы подмените для этой абстракции реализацию, работать не будет, следовательно, это говнокод. То есть абстракция тут хоть и есть, но она абсолютно бессмыслена и бесполезна

Пример ковариативности\контрвариантивности
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
using System;

namespace GenericVariance
{
    //Ковариативный тип
    interface ICovariance<out T>
    {
        T GetValue();
    }

    //Контрвариативный тип
    interface IContrvariance<in T>
    {
        void SetValue(T value);
    }

    //Инвариативный тип
    interface IInvariance<T> : ICovariance<T>, IContrvariance<T> { }
    
    // Тип реализующий наши интерфейсы
    public class Example<T> : IInvariance<T>
    {
        private T _value;
        public T GetValue()
        {
            return _value;
        }

        public void SetValue(T value)
        {
            _value = value;
        }
    }

    //Абстрактный тип модели описывающий человека
    abstract class Person
    {
        public string Name { set; get; }
        public int Age { set; get; }

        public override string ToString()
            => $"Person: {Name}, {Age}";
    }

    //Тип модели описывающий сотрудника, наследуется от Person
    class Employee : Person
    {
        public string Title { set; get; }
        public string Department { set; get; }

        public override string ToString()
            => $"Employee : {Name}, {Age}, {Title}, {Department}";
    }

    class Program
    {
        static void Main(string[] args)
        {
            //Создаем экземпляр типа реализующий наши интерфейсы
            Example<Person> a = new Example<Person>();

            //Приводим к контрвариантному интерфейсу IContrvariance<Employee> 
            IContrvariance<Employee> c = (IContrvariance<Employee>)a;
            c.SetValue(new Employee() 
            { 
                Name = "Roman Meytes", 
                Age = 31, 
                Title = "Developer", 
                Department = "Backend Department"
            });

            //Приводим наш тип к ковариантному интерфейсу ICovariance<object>
            ICovariance<object> b  = (ICovariance<object>)a;
            object obj = b.GetValue();
            Console.WriteLine(obj.ToString());

            try
            {
                //На этих двух строках произойдет ошибка приведения типа 
                //в момент выполнения (RunTime)
                IInvariance<object> d = (IInvariance<object>)a;
                IInvariance<Employee> e = (IInvariance<Employee>)a;
            }
            catch (Exception ex)
            {
                Console.Write(ex.ToString());
            }
        }
    }
}

...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903410
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hVostt
Nechto
Понять не могу, в чем говнокод? Простое приведение интерфейса к классу.
Объясните пожалуйста


Чего тут объяснять? Суть интерфейса в сокрытии реализации.
Когда вы приводите интерфейс к классу, смысл в интерфейсе пропадает начисто.
Передавайте всё тупо через ссылку на object тогда и везде приводите к нужному классу.
Посмотрите что ваши коллеги на это скажут ))


Я вас понял. Почему тогда это не говно код? Потому что Entity1 уже реализован?

Код: c#
1.
2.
3.
Entity1 entity = new Entity1();
IBase ibase = entity as IBase;
entity  = (Entity1)ibase;
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903411
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nechto
hVostt
пропущено...


Чего тут объяснять? Суть интерфейса в сокрытии реализации.
Когда вы приводите интерфейс к классу, смысл в интерфейсе пропадает начисто.
Передавайте всё тупо через ссылку на object тогда и везде приводите к нужному классу.
Посмотрите что ваши коллеги на это скажут ))


Я вас понял. Почему тогда это не говно код? Потому что Entity1 уже реализован?

Код: c#
1.
2.
3.
Entity1 entity = new Entity1();
IBase ibase = entity as IBase;
entity  = (Entity1)ibase;

кто сказал, что это не говнокод? даже в рамках одного метода, какой в этом смысл?
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903580
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nechto
Я вас понял. Почему тогда это не говно код? Потому что Entity1 уже реализован?

Код: c#
1.
2.
3.
Entity1 entity = new Entity1();
IBase ibase = entity as IBase;
entity  = (Entity1)ibase;



смотрите, я вам покажу какую штуку:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
using System;
using System.Linq.Expressions;

namespace Test
{
    public interface IBase { int Id { get; set; } }
    public class Run
    {
        public Run()
        {
            /// Expression<Func<IBase, bool>> filter = x => x.Id == 1;
            var a1 = new A1(x => x.Id == 1); // теперь всё работает!
        }
    }

    public class A1 : AbstrReload<Entity1>
    {
        public A1(Expression<Func<Entity1, bool>> filter)
        {
            Reload(filter); // теперь всё соответствует
        }
    }

    public abstract class AbstrReload<TEntity>
        where TEntity : class, IBase
    {
        protected void Reload(Expression<Func<TEntity, bool>> filter)
        {
        } 
    }

    public class Entity1 : IBase
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class Entity2 : IBase
    {
        public int Id { get; set; }
        public string Caption { get; set; }
    }
}



что мы сделали? стали использовать Lambda Expression по прямому назначению:

Код: c#
1.
2.
3.
var a1 = new A1(x => x.Id == 1); // вот так лямбды используются

Expression<Func<IBase, bool>> filter = x => x.Id == 1; // а вот так не используются!!



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

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

обратите внимание на интерфейс IQueryable<T> -- вместо того, чтобы собирать ваше условие отдельно и передавать, вы собираете результат каждый раз получая новый результат после применения операции:

query.Where(...).Where(...).Where(...)

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

дальше будет -- хуже. я вам обещаю, это ещё цветочки. огребёте граблями по всему прыщавому лбу ))
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903743
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt
дальше будет -- хуже. я вам обещаю, это ещё цветочки. огребёте граблями по всему прыщавому лбу ))

...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903868
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hVostt
дальше будет -- хуже. я вам обещаю, это ещё цветочки.

Согласен! Похоже, что я хочу концепция c# не хочет) Видимо нужно менять структуру проекта.
Либо не хватает знаний, для того чтобы создавать универсальные алгоритмы работы с типами в реалтайме(
Короче, я уже сам запутался.

Код: c#
1.
2.
3.
4.
5.
// Ваш пример:
var a1 = new A1(x => x.Id == 1); // теперь всё работает!

// Это вариант уже создаёт проблему в реализации!
var a1 = Activator.CreateInstance(typeof(A1), /* вот как тут объявишь expression в реалтайме, если знаешь только getType() объекта (Entity1 или Entity2)? */)
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39903884
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nechto
Либо не хватает знаний, для того чтобы создавать универсальные алгоритмы работы с типами в реалтайме(
Короче, я уже сам запутался.

Код: c#
1.
2.
3.
4.
5.
// Ваш пример:
var a1 = new A1(x => x.Id == 1); // теперь всё работает!

// Это вариант уже создаёт проблему в реализации!
var a1 = Activator.CreateInstance(typeof(A1), /* вот как тут объявишь expression в реалтайме, если знаешь только getType() объекта (Entity1 или Entity2)? */)



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

обратите внимания на паттерны и принципы разработки (GOF, SOLID, KISS..)

Expression в рантайме тоже используется, и активно, но не для лямбд
для генерации кода, оптимизации, но не для целевых задач
...
Рейтинг: 0 / 0
c# не соответствие классов с интерфейсом
    #39904124
Nechto
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hVostt

Expression в рантайме тоже используется, и активно, но не для лямбд
для генерации кода, оптимизации, но не для целевых задач


Чтобы дожать тему, решил сегодня поразбираться и вот что у меня получилось:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
// Ваш пример:
var a = new A1(x => x.Id == 1); // теперь всё работает!
           
// Создание лямбды при помощи expression, в реалтайме ( когда знаем только типы объектов (getType()) ) 
ParameterExpression parametr = Expression.Parameter(typeof(Entity1), "x");
MemberExpression property = Expression.Property(parametr, "Id");
BinaryExpression equal = Expression.Equal(property, Expression.Constant(1));
var delegateType = typeof (Func<,>).MakeGenericType(typeof(Entity1), typeof(bool));
var runtimeExpression = Expression.Lambda(delegateType, equal, parametr);
var classA1Creator = Activator.CreateInstance(typeof(A1), runtimeExpression);


Так активно используют Expression в реалтайме? Или этот код, тоже можно отнести к мусорному?
...
Рейтинг: 0 / 0
25 сообщений из 29, страница 1 из 2
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / c# не соответствие классов с интерфейсом
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]