Помогите правильно написать ограничение дженерик-метода
От: faa  
Дата: 08.02.14 14:49
Оценка:
Доброго времени суток! Прошу помощи.

Задача:
Написать коллекцию из которой можно извлекать значения по идентификатору без упаковки\распаковки в "System.Object".
Для решения этой задачи пробую использовать дженерик-метод:


        class Program
    {
        static Dictionary<long, byte> _hashByte = new Dictionary<long, byte>();
        static Dictionary<long, bool> _hashBoolean = new Dictionary<long, bool>();
        static Dictionary<long, int> _hashInt32 = new Dictionary<long, int>();
        static Dictionary<long, long> _hashInt64 = new Dictionary<long, long>();
                        
        // Возвращает значение по идентификатору
        public static T GetValue<T>(long id) where T : struct
        {            
            T value = default(T);

            switch (typeof(T).Name)
            {
                case "Byte":
                    value = (T)_hashByte[id];
                    break;
                case "Boolean":
                    value = (T)_hashBoolean[id];
                    break;
                case "Int32":
                    value = (T)_hashInt32[id];
                    break;
                case "Int64":
                    value = (T) _hashInt64[id];
                    break;
            }
            return value;
        }

        static void Main(string[] args)
        {
            long value = GetValue<long>(1);
        }
    }

Получаю сообщение компилятора:
" Cannot convert type 'byte' to 'T' "
" Cannot convert type 'bool' to 'T' "
...

Как правильно написать ограничение на значимый тип?
В идеале нужен дженерик-метод, который может возвращать значения значимых типов C# и ссылочный тип string — такое возможно?

Заранее благодарен!
Re: Помогите правильно написать ограничение дженерик-метода
От: Lloyd Россия  
Дата: 08.02.14 15:08
Оценка:
Здравствуйте, faa, Вы писали:

faa>Задача:

faa>Написать коллекцию из которой можно извлекать значения по идентификатору без упаковки\распаковки в "System.Object".
faa>Для решения этой задачи пробую использовать дженерик-метод:
faa>...
faa>Как правильно написать ограничение на значимый тип?

Дело не в ограничении на тип, с ним у вас все правильно.
Самое простое, что напрашивается:
1. В свитче делать не поиск значения, а поиск словаря, из которого делать лукап.
2. В case-ах делать сначала каст словаря к object-у, и только потом к целевому типу словаря.
Dictionary<long, T> valueDictionary; // local variable
...
case...:
  valueDictionary = (Dictionary<long, T>)(object)intDictionary:
...
return valueDictionary[id];

Боксинга не будет, т.к. Dictionary — ссылочный тип.

А если по-чесноку, я бы написал по-другому:
private static class ValuesProvider<TKey, TValue>
{
    public static readonly IDictionary<TKey, TValue> Values = new Dictionary<TKey, TValue>();
}
                
// Возвращает значение по идентификатору
public static T GetValue<T>(long id) where T : struct
{
    return ValuesProvider<long, T>.Values[id];
}

Правда, х его з, будет ли это работать. Возможности проверить нет
Re[2]: Помогите правильно написать ограничение дженерик-метода
От: Аноним  
Дата: 08.02.14 15:32
Оценка:
L>Здравствуйте, faa, Вы писали:
L>А если по-чесноку, я бы написал по-другому:
L>
L>private static class ValuesProvider<TKey, TValue>
L>{
L>    public static readonly IDictionary<TKey, TValue> Values = new Dictionary<TKey, TValue>();
L>}
                
L>// Возвращает значение по идентификатору
L>public static T GetValue<T>(long id) where T : struct
L>{
L>    return ValuesProvider<long, T>.Values[id];
L>}
L>

L>Правда, х его з, будет ли это работать. Возможности проверить нет
не будет: string — это не struct
Re[3]: Помогите правильно написать ограничение дженерик-метода
От: Lloyd Россия  
Дата: 08.02.14 15:39
Оценка:
Здравствуйте, Аноним, Вы писали:

L>>// Возвращает значение по идентификатору

L>>public static T GetValue<T>(long id) where T : struct
L>>{
L>> return ValuesProvider<long, T>.Values[id];
L>>}
L>>[/c#]
L>>Правда, х его з, будет ли это работать. Возможности проверить нет
А>не будет: string — это не struct

Были сомнения в работоспособности варианта с приватным generic-классом.
То, что класс не будет работать со строками — это и так понятно.
Re[2]: Помогите правильно написать ограничение дженерик-метода
От: Аноним  
Дата: 08.02.14 18:25
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, faa, Вы писали:


faa>>Задача:

faa>>Написать коллекцию из которой можно извлекать значения по идентификатору без упаковки\распаковки в "System.Object".
faa>>Для решения этой задачи пробую использовать дженерик-метод:
faa>>...
faa>>Как правильно написать ограничение на значимый тип?

L>Дело не в ограничении на тип, с ним у вас все правильно.

L>Самое простое, что напрашивается:
L>1. В свитче делать не поиск значения, а поиск словаря, из которого делать лукап.
L>2. В case-ах делать сначала каст словаря к object-у, и только потом к целевому типу словаря.
L>
L>Dictionary<long, T> valueDictionary; // local variable
L>...
L>case...:
L>  valueDictionary = (Dictionary<long, T>)(object)intDictionary:
L>...
L>return valueDictionary[id];
L>

L>Боксинга не будет, т.к. Dictionary — ссылочный тип.

L>А если по-чесноку, я бы написал по-другому:

L>
L>private static class ValuesProvider<TKey, TValue>
L>{
L>    public static readonly IDictionary<TKey, TValue> Values = new Dictionary<TKey, TValue>();
L>}
                
L>// Возвращает значение по идентификатору
L>public static T GetValue<T>(long id) where T : struct
L>{
L>    return ValuesProvider<long, T>.Values[id];
L>}
L>

L>Правда, х его з, будет ли это работать. Возможности проверить нет

<В свитче делать не поиск значения, а поиск словаря, из которого делать лукап.> Не понял идею.. Можно пример?


    static class ValuesProvider<TKey, TValue>
    {
        private static IDictionary<TKey, TValue> _values = new Dictionary<TKey, TValue>();
        
        // Возвращает значение по идентификатору
        public static T GetValue<T>(long id) where T : struct
        {
            return ValuesProvider<long, T>._values[id];
        }

        public static void SetValue<T>(long id, T value) where T: struct
        {
            ValuesProvider<long, T>._values.Add(id, value);   
        }
    }                

    class Program
    {
        static void Main(string[] args)
        {
            ValuesProvider<long, bool>.SetValue<bool>(0, true);
            ValuesProvider<long, int>.SetValue<int>(0, 12345);
            Console.WriteLine(ValuesProvider<long, bool>.GetValue<bool>(0));
            Console.WriteLine(ValuesProvider<long, int>.GetValue<int>(0));
        }
    }

Это действительно работает, но я не пойму как? Я правильно понимаю, что вся "магия" заключается в использовании именно статического класса? Если не трудно поясните, как это работает?
Re: Помогите правильно написать ограничение дженерик-метода
От: vorona  
Дата: 09.02.14 06:58
Оценка:
Здравствуйте, faa, Вы писали:
    abstract class Value
    {
        public abstract K GetValue<K>();
        public static Value Create<T>(T value)
        {
            return new Value<T>(value);
        }
    }
    sealed class Value<T> : Value
    {
        private T _value;
        public Value(T value)
        {
            _value = value;
        }
        public override K GetValue<K>()
        {
            return __refvalue( __makeref(_value),K); ;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Value value = Value.Create(42);
            Console.WriteLine(value.GetValue<int>());
        }
    }
Re: Помогите правильно написать ограничение дженерик-метода
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.02.14 17:40
Оценка:
Здравствуйте, faa, Вы писали:

faa>Доброго времени суток! Прошу помощи.


faa>Задача:

faa>Написать коллекцию из которой можно извлекать значения по идентификатору без упаковки\распаковки в "System.Object".
Задача — понятна.
faa>Для решения этой задачи пробую использовать дженерик-метод:
Зачем? Вот правильное решение:

class Program
    {
        static Dictionary<long, byte> _hashByte = new Dictionary<long, byte>();
        static Dictionary<long, bool> _hashBoolean = new Dictionary<long, bool>();
        static Dictionary<long, int> _hashInt32 = new Dictionary<long, int>();
        static Dictionary<long, long> _hashInt64 = new Dictionary<long, long>();
                        
        // Возвращает значение по идентификатору
        public static byte GetValueByte(long id)
        {            
            return _hashByte[id];
        }
        // Возвращает значение по идентификатору
        public static bool GetValueBool(long id)
        {            
            return _hashBoolean[id];
        }
        // Возвращает значение по идентификатору
        public static int GetValueInt(long id)
        {            
            return _hashInt32[id];
        }
        // Возвращает значение по идентификатору
        public static long GetValueLong(long id)
        {            
            return _hashInt64[id];
        }


        static void Main(string[] args)
        {
            long value = GetValueLong(1);
        }
    }


faa>Как правильно написать ограничение на значимый тип?

Никак.
faa>В идеале нужен дженерик-метод, который может возвращать значения значимых типов C# и ссылочный тип string — такое возможно?
Без боксинга — нет. Непонятна цель ваших действий. Вызывающий код обязан указать нужный ему тип данных. При этом вы умеете возвращать вовсе не любой тип, а только один из известных вам заранее типов.
Фактически, дженерик-версия отличается от моей версии только наличием угловых скобочек в месте вызова метода. Ну и тем, что компилятор не проверяет, поддерживаемый ли тип передан в аргументе.
Вы нигде не используете тот факт, что ваш метод — generic.
faa>Заранее благодарен!
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.