Преобразовашки...

Общие вопросы о Unity3D

Преобразовашки...

Сообщение 1max1 05 окт 2018, 02:19

Есть такой вот словарь:
Синтаксис:
Используется csharp
Dictionary<Type, Dictionary<int, Base>> d = new Dictionary<Type, Dictionary<int, Base>>();

Выглядит мощно, знаю, суть не в этом. Base является базовым классом для классов A, B, C к примеру:
Синтаксис:
Используется csharp
class Base { }
class A : Base { }
class B : Base { }
class C : Base { }

Я пытаюсь сделать метод, который бы вернул словарь из d преобразованный в наследуемый тип, например Dictionary<int, A>. Но простой as не может этого сделать, а создавать новый словарь и заполнять его элементами из d слишком затратно.
Вот пример метода возврата:
Синтаксис:
Используется csharp
Dictionary<int, T> GetAllElements<T>() where T : Base
{
    return d[typeof(T)] as Dictionary<int, T>;
}

Но как я уже сказал так не канает, выдает NullReferenceException. Мне это нужно для прохода по циклу в другом коде, к примеру так:
Синтаксис:
Используется csharp
foreach (A a in GetAllElements<A>())
{
    // bla bla bla
}

Если сделать так:
Синтаксис:
Используется csharp
Dictionary<int, Base> GetAllElements<T>() where T : Base
{
    return d[typeof(T)];
}

То цикл работать будет, НО! Не всегда хочется указывать тип напрямую для преобразования (лучше использовать var), но если юзануть var, то получится не тип А, а тип Base, что не комильфо...

п.с. Можно через линкью, но я не уверен в его производительности, что вы думаете на этот счет?
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Преобразовашки...

Сообщение alt3d 05 окт 2018, 08:43

Dictionary<int, T> GetAllElements<T>() where T : Base
{
return d[typeof(T)] as Dictionary<int, T>;
}


Вместо словаря сделай лучше получение коллекции:
Синтаксис:
Используется csharp
IEnumerable<T> GetAllElements<T>() where T : Base
{
    return d[typeof(T)].Values;
}
alt3d
Старожил
 
Сообщения: 687
Зарегистрирован: 04 сен 2011, 21:19
  • Сайт
  • ICQ

Re: Преобразовашки...

Сообщение 1max1 05 окт 2018, 09:42

На такое преобразование тоже ругается, только так:
Синтаксис:
Используется csharp
IEnumerable<Base> GetAllElements<T>() where T : Base
{
    return d[typeof(T)].Values;
}
 

:(
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Преобразовашки...

Сообщение alt3d 05 окт 2018, 09:59

А, ну да, логично )
Тогда ждем что скажут тру-программисты
alt3d
Старожил
 
Сообщения: 687
Зарегистрирован: 04 сен 2011, 21:19
  • Сайт
  • ICQ

Re: Преобразовашки...

Сообщение jetyb 05 окт 2018, 10:08

Неплохая задача.
Думаю, что решить можно через ковариантные интерфейсы, которые позволяют преобразования к унаследованным типам.
Было бы вместо вложенного Dictionary ковариантное IEnumerable - и париться бы не пришлось. А так надо писать свой ковариантный IMyDictionary.

Проблема в том, что нельзя сделать нормальный ковариантный интерфейс типа IMyDictionary, потому что
Синтаксис:
Используется csharp
interface IMyDictionary<TKey, out TValue>
{
       void Add(TKey key, TValue>(); //не скомпилируется
       TValue GetValue(TKey key); // а так можно
}
 

нельзя делать ковариантые переменные входными параметрами метода.


Придется делать свой недо-IDictionary с одним методом
Синтаксис:
Используется csharp
        interface IMyDic<out TValue>
        {
            TValue GetValue(int key);
        }
        class MyDic<TValue> : IMyDic<TValue>
        {
            public readonly Dictionary<int, TValue> dictionary = new Dictionary<int, TValue>();

            public TValue GetValue(int key) => dictionary[key];
        }
Dictionary<Type, IMyDic<Base>> d;
IMyDic<TValue> GetAllElements<TValue>()
{
      var els = d[typeof(TValue)];
      return els as IMyDic<TValue>;
}
 

Проверка работы:
Синтаксис:
Используется csharp
void Test()
{
            var e1 = new MyDic<A>
            {
                dictionary =
                {
                    {1, new A()}, {2, new A()}
                }
            };
            var e2 = new MyDic<B>
            {
                dictionary =
                {
                    {2, new B()}, {3, new B()}
                }
            };
            var e3 = new MyDic<C>
            {
                dictionary =
                {
                    {4, new C()}, {5, new C()}
                }
            };

            d = new Dictionary<Type, IMyDic<Base>>
            {
                {typeof(A), e1},
                {typeof(B), e2},
                {typeof(C), e3},
            };

            var h = GetAllElements<B>();
}
 
jetyb
Адепт
 
Сообщения: 1486
Зарегистрирован: 31 окт 2011, 17:21

Re: Преобразовашки...

Сообщение 1max1 05 окт 2018, 10:18

Мда... всё не так просто как хотелось :-? В любом случае спасибо, придется теперь разбирать в интерфейсах)
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Преобразовашки...

Сообщение alt3d 05 окт 2018, 11:36

jetyb писал(а):return els as IMyDic<TValue>;

А насколько это сильно бьет по производительности? И вообще применимо?
Вроде никогда не видал чтобы так преобразовывали коллекции.
Прям ваще пипец как плохо, или в пределах нормы и ради удобства допустимо?
alt3d
Старожил
 
Сообщения: 687
Зарегистрирован: 04 сен 2011, 21:19
  • Сайт
  • ICQ

Re: Преобразовашки...

Сообщение 1max1 05 окт 2018, 12:56

Конечно, словарь, да еще и с преобразованиями, будет давать о себе знать. Я это затеял ради удобства, но немного поковырявшись, понял, что лучше всё переделать по другому) Изначально задумка была для ECS, чтобы можно было из словаря брать сразу все нужные сущности определенного типа и потом работать с готовым списком, но как я понял ни LINQ ни словари (еще и с преобразованиями) не дадут хорошей производительности по сравнению с тем же списком, а уж тем более простым массивом.
Так что удобство, думаю отпадает)
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51


Вернуться в Общие вопросы

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4