Разнородный словарь, но набранный?

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

myDict.Add("Name", "Bill"); 
myDict.Add("Height", 1.2); 

где myDict теперь содержит в качестве значений не два типа object, а один string и один double? Тогда я мог бы получить свой double с помощью

double dbl = myDict["Height"];

и ожидаете, что будет сгенерировано двойное или исключение?

Обратите внимание: значения Name и Height не обязательно относятся к одному и тому же объекту.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
0
1 183
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Вы можете использовать Generic Dictionary<object, object>; тип объекта для ключа и тип объекта для значения. C# может помочь.

По какой причине вы не можете создать класс / структуру и поместить это в список или словарь? В противном случае вы могли бы просто обернуть класс словаря своим собственным и установить ограничения таким образом.

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

Я не понимаю, почему вам нужно делать что-то таким образом - возможно, стоит переделать вашу программу?

Мне не нужно так поступать. Мне не нужно ничего делать, кроме как исследовать, что можно сделать.

ProfK 28.11.2008 00:21

Ключи все струны? тогда Dictionary<string,object>, вероятно, выполнит эту работу ... но при получении значений вам либо нужно будет использовать object, либо вам нужно будет преобразовать:

double dbl = (double)myDict["Height"];
object height = myDict["Height"];

Причина, по которой я задал вопрос, заключалась в том, чтобы избежать использования значений dic как объектов. Если я сохраняю двойное, мне нужно двойное назад, а не «объект с двойной экспозицией», который я должен использовать.

ProfK 28.11.2008 00:20

@Profk - вы обманываете себя, если думаете, что Get <int> (...) отличается от (int) Get (...). Ну что ж...

Marc Gravell 28.11.2008 03:01

@MarcGravell неправда. Если класс внутренне обеспечивает связь между типом и его значением при вставке, то извлечение, требующее внутреннего приведения, будет полностью безопасным (небезопасным для компилятора, но безопасным при условии, что код является внутренне правильным). Никакой внешний вызывающий объект не будет способный, чтобы вызвать недопустимое приведение на основе несоответствия типа ключ / значение. Они либо получат типизированное значение, либо вернут нулевое значение, и это будет полностью типобезопасно с их точки зрения. Теоретически недопустимые исключения при приведении типов никогда не возникнут ни внутри контейнера, ни за его пределами.

AaronHS 03.04.2015 08:50

@AaronHS Я не понимаю, как это вообще имеет значение; в этом случае и (int)Get(...), и Get<int>(...) будут работать, но они уже работают (или нет) вместе. Все, что мы сделали, это переместили гипс. Возвращать null, потому что кто-то ошибся в типе, - плохой ход; нужно сделать правильный: недопустимое исключение приведения.

Marc Gravell 07.04.2015 10:41

@MarcGravell проблема не в том, что somebody got the type wrong. Проблема в том, что кто-то наивно связал ключ со значением одного типа, скажем, string: (1) dict.Add("myKey!", "myStringValue!"). Позже тот же кто-то пытается получить это значение: (2) возникает исключение приведения типов string unsafeStr = (string)dict["myKey!"] и хлопнуть. Но почему? Другой считал, что myKey! - отличный ключ для значения int, и где-то между (1) и (2) была выполнена эта строка кода: dict["myKey!"] = 123. Здесь (string)Get терпит неудачу, но Get<String> преуспевает и сохраняет согласованность.

yair 07.02.2018 19:09

@yair и я утверждаем, что лучшее, что может здесь случиться - это сбой, чтобы предупредить вас о проблеме; очень редко хорошие дела возникают из-за игнорирования проблем.

Marc Gravell 07.02.2018 19:14

@MarcGravell, поскольку я пришел с Java, я должен сказать, что отдельные методы для добавления нового значения или перезаписи существующего в словарь - могут оказаться большим подспорьем для предотвращения случая, о котором я упоминал в предыдущем комментарии. В Java за обе ошибки отвечает один и тот же метод put, поэтому он более подвержен ошибкам такого рода. Итак, в C# я действительно не уверен, что эти хлопоты стоят небольшого выигрыша в безопасности типов.

yair 07.02.2018 19:16

@MarcGravell Я в целом согласен. Причиной написания такого специального служебного класса должна быть не слабая попытка предотвратить какую-либо маловероятную ошибку (или вероятную), а то, что он добавляет некоторые необходимые функции, которые отсутствуют в основных библиотеках. Итак, +1! (Я потратил часы на поиск лучшего решения)

yair 07.02.2018 19:19

Если типы являются классами, ничто не мешает вам взаимодействовать с обоими и помещать экземпляры в словарь <foo, IYourInterface>

Может быть. Может быть, что-то вроде IPresentationElementValue. Пища для размышлений.

ProfK 27.11.2008 16:28

Словарь БУДЕТ содержать строку и двойное значение в качестве значений, но двойное будет заключено в рамку.

Как компилятор мог проверить то, о чем вы спрашиваете? Как он мог узнать во время компиляции, какой тип объекта относится к каждому ключу?

Идея состоит не в том, чтобы знать во время компиляции, а в том, чтобы использовать ключ для определения возвращаемого типа. C# движется к включению некоторых захватывающих динамических концепций, и я полагаю, что это может остаться незамеченным.

ProfK 28.11.2008 00:18

Словарь не подходит для этого. Вам действительно нужен класс Person для хранения этих значений.

И с помощью классов намного проще создавать коллекции и вылавливать ошибки.

Обновлено:

Поскольку вам нужен полу-строго типизированный dict:

public class CustomDictionary : Dictionary<string,object>
{
    public T GetTyped<T>(string key) where T : IConvertible
    {
        return (T)Convert.ChangeType(base[key], typeof (T));
    }
}

Использование:

CustomDictionary dictionary = new CustomDictionary();

dictionary.Add("Test",1.2);

var d = dictionary.GetTyped<double>("Test");

Значения не обязательно должны быть связаны с одним и тем же объектом, как это случайно подразумевается в моем примере. Имя могло быть как у собаки, а Рост - как у стола.

ProfK 27.11.2008 16:27

Ох, хорошо. Вам нужен CustomDictonary, который расширяет Dictionary <string, object> и добавляет метод GetTyped <Type> (строковый ключ) :)

Lars Mæhlum 27.11.2008 16:47
Ответ принят как подходящий

Единственный способ сделать это, если у вас есть настраиваемая коллекция с универсальными перегрузками для методов Add и Get. Но это будет означать, что вы можете запросить неправильный тип при чтении ключа, поэтому это не принесет вам много (если вообще что-либо), если вы сами выполняете приведение, когда вы вызываете свой метод Get.

Однако, если вы можете вставить общий тип в ключ, это может сработать. Что-то вроде (здесь непроверенный код)

sealed class MyDictionaryKey<T>
{
}

class MyDictionary
{
    private Dictionary<object, object> dictionary = new Dictionary<object, object>();

    public void Add<T>(MyDictionaryKey<T> key, T value)
    {
        dictionary.Add(key, value);
    }

    public bool TryGetValue<T>(MyDictionaryKey<T> key, out T value)
    {
      object objValue;
      if (dictionary.TryGetValue(key, out objValue))
      {
        value = (T)objValue;
        return true;
      }
      value = default(T);
      return false;
    }

    public T Get<T>(MyDictionaryKey<T> key)
    {
      T value;
      if (!TryGetValue(key, out value))
         throw new KeyNotFoundException();
      return value;
    }
}

Затем вы можете определить свои ключи следующим образом:

static readonly MyDictionaryKey<string> NameKey = new MyDictionaryKey<string>();
static readonly MyDictionaryKey<double> HeightKey = new MyDictionaryKey<double>();

и используйте это как

var myDict = new MyDictionary();
myDict.Add(NameKey, "Bill"); // this will take a string
myDict.Add(HeightKey , 1.2); // this will take a double

string name = myDict.Get(NameKey); // will return a string
double height = myDict.Get(HeightKey); // will return a double

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

ProfK 27.11.2008 16:24

Другие вопросы по теме