powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / LINQ Cast<T> метод работает как то странно
4 сообщений из 4, страница 1 из 1
LINQ Cast<T> метод работает как то странно
    #39081513
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Суть такая: есть класс Person и класс CheckedPerson который наследуется от класса IsCheckedWrapper<Person>, который в свою очередь наследуется от класса BaseWrapper<T>, в котором переопределен оператор implicit, преобразование из типа BaseWrapper<T> в T (как к примеру в Nullable<T> классе). С виду всё прилично работает, у меня есть объект класс CheckedPerson , я могу его в коде скастить в Person без лишних усилий и свойств.
Затем создаю коллекцию объектов CheckedPerson и пытаюсь скастить их через Cast<T> и мне выдается ошибка о том, что я не могу преобразовать CheckedPerson в Person.
Смотрим в код метода Cast<T> и видим, что перед тем как преобразовать в заданный тип, объект сперва приводится к классу object, а уже из класса object, он не может "прикастить" его Person.

как то можно решить эту проблему?


Код: 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.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApplication27
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var persones = new List<CheckedPerson>()
            {
                new CheckedPerson(new Person("Roman", 31)),
                new CheckedPerson(new Person("Sofia", 36)),
                new CheckedPerson(new Person("Alexandr", 14)),
                new CheckedPerson(new Person("Olga", 6))
            };

            foreach (Person i in persones)
                Console.WriteLine("Name: {0}, Age: {1}", i.Name, i.Age);
            
            Console.ReadKey();

            foreach (var i in persones.Cast<Person>())
                Console.WriteLine("Name: {0}, Age: {1}", i.Name, i.Age);

        }

        
    }

    public class CheckedPerson : IsCheckedWrapper<Person>
    {
        public CheckedPerson(Person source) : base(source) {}
    }

    public class Person
    {
        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }
        public string Name { private set; get; }
        public int Age { private set; get; }
    }

    public class IsCheckedWrapper<T> : BaseWrapper<T>
    {
        public static IsCheckedWrapper<T> Factory(T source)
        {
            return new IsCheckedWrapper<T>(source);
        }
        public IsCheckedWrapper(T source) : base(source) { }
        public bool IsChecked { set; get; }
    }

    public class BaseWrapper<T>
    {
        private readonly T _source;

        public BaseWrapper(T source)
        {
            _source = source;
        }

        public T Source
        {
            get { return _source; }
        }


        public override bool Equals(object obj)
        {
            if (obj is BaseWrapper<T>)
                return Equals((BaseWrapper<T>)obj);

            return false;
            
        }
        public bool Equals(BaseWrapper<T> other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return _source.Equals(other._source);
        }
        public override int GetHashCode()
        {
            return _source.GetHashCode();
        }

        public static explicit operator T (BaseWrapper<T> wrapper)
        {
            if (wrapper == null) return default(T);
            return wrapper.Source;
        }

        public static bool operator ==(BaseWrapper<T> left, BaseWrapper<T> right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(BaseWrapper<T> left, BaseWrapper<T> right)
        {
            return !Equals(left, right);
        }
    }
}

...
Рейтинг: 0 / 0
LINQ Cast<T> метод работает как то странно
    #39081538
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вообще точно такая же ситуация с Nullable<T> работает отлично, самое обидное, что это уже не 1 раз, когда Nullable<T> класс имеет какие то преференции в отличии от других классов. Так например при связывании в WPF преобразование класса Nullable<T> в T происходит неявно и прозрачно, в то время как все остальные Generic классы с определенными операторами преобразования от...т.
До коле это будет продолжаться?
...
Рейтинг: 0 / 0
LINQ Cast<T> метод работает как то странно
    #39081615
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,

Explici/implicit преобразования вставляются компилятором во время компиляции, поскольку он обладает всей необходимой информацией, и может подставить op_Explicit/op_Emplicit в точку преобразования. Cast<T> работает на рантайме, и использует generic cast; никакой информации о наличии операторов преобразования у компилятора нет, соответственно, нет вставки в IL-код op_Explicit/op_Emplicit. Остается только сравнение типов "в лоб" по иерархии, которое дает отрицательный резальтат - вот Cast и рвется.
А у Nullable<T> поддержка таких преобразований зашита на уровне CLR, и странно требовать от фреймворка наличия такой поддержки для любого пользовательского класса.
Обо всём этом я уже именно вам писал здесь: 17996905 .
...
Рейтинг: 0 / 0
LINQ Cast<T> метод работает как то странно
    #39081781
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры ПавловныRoman Mejtes,

Explici/implicit преобразования вставляются компилятором во время компиляции, поскольку он обладает всей необходимой информацией, и может подставить op_Explicit/op_Emplicit в точку преобразования. Cast<T> работает на рантайме, и использует generic cast; никакой информации о наличии операторов преобразования у компилятора нет, соответственно, нет вставки в IL-код op_Explicit/op_Emplicit. Остается только сравнение типов "в лоб" по иерархии, которое дает отрицательный резальтат - вот Cast и рвется.
А у Nullable<T> поддержка таких преобразований зашита на уровне CLR, и странно требовать от фреймворка наличия такой поддержки для любого пользовательского класса.
Обо всём этом я уже именно вам писал здесь: 17996905 .
да я понимаю и помню, что вы писали, я тогда уже сам пришел к тому же ответу, что и вы.
проблема тут в том, что
а) Cast<T>() реализован не для IEnumerable<T>, а от IEnumerable, в результате в перечисляются объекты класс object, а так как у object требуемый оператор не переопределен, я получаю ошибку. Так как моих классах нет наследования, а только переопределен оператор. + как я понял, невозможно скастить TResult тип в TSource, если они не наследуют друг друга и это не указано в условии.
В результате я думал, думал, забил и использую .Select(p => (Person)p) и всё работает :) точно также, не думаю даже, что особо тормознутее :)
...
Рейтинг: 0 / 0
4 сообщений из 4, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / LINQ Cast<T> метод работает как то странно
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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