Кастинг значения к T в общем методе

Я собираюсь догадаться, что «игнорирование пропущенных значений» означает «трактовать их как нули». Если у вас есть другая идея, вы должны сделать это явно.

Это может быть

gen new_var = (cond(missing(X), 0, 3 * X) ///
+ cond(missing(Y), 0, 2 * Y) ///
+ cond(missing(Z), 0, 4 * Z)) / 7 

Давайте посмотрим на ваши решения и объясним, почему они все не правы в целом или обычно.

(cond(missing(X*3),., X) + cond(missing(Y*2),., Y))/7 

Достаточно отметить, что если верно, что X отсутствует, то cond() приводит к отсутствию, как тогда X * 3 также отсутствует. Такое же замечание относится к терминам, включающим Y и Z. Таким образом, вы заменяете все пропущенные значения пропущенными значениями, а это не усиление

!missing(X*3+Y*2+Z*4)/7

Учитывая информацию, что по крайней мере один из X Y Z всегда отсутствует, тогда это всегда оценивается как 0/7 или 0. Даже если бы X Y Z были все не пропущены, тогда он оценил бы до 1/7. Это далеко от суммы, которую вы хотите. missing() всегда дает 1 или 0, а его отрицание, таким образом, 0 или 1.

(max(X, Y, Z)/7) if missing(X , Y, Z) 

Максимум X, Y, Z будет правильным ответом, если и только если один из значений не пропущены, а два других отсутствуют. max() в максимально возможной степени игнорирует пропуски (хотя в других контекстах пропуски рассматриваются как произвольно большие положительные числа). [+1121]

15
задан Loofer 5 March 2015 в 17:18
поделиться

5 ответов

I believe this is because the compiler doesn't know what type of operation it needs to perform. IIRC, you can get it to work if you introduce boxing:

if (typeof(T) == typeof(int)) return (T)(object)map.GetInt(key);

but that's not ideal in terms of performance.

I think it's just a limitation of generics, unfortunately.

29
ответ дан 1 December 2019 в 01:31
поделиться

What do GetInt, GetString etc do internally? There may be other options involving Convert.ChangeType(...) or TypeDescriptor.GetConverter(...).ConvertFrom(...), and a single cast, using an "object" indexer:

for example, if the objects are already correctly typed:

public T GetOrDefault<T>(this IPropertyMap map, string key, T defaultValue)
{
    return map.Exists(key) ? (T)map[key] : defaultValue;
}

or if they are stored as strings and need conversion, something involving:

T typedVal = (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(map[key]);
3
ответ дан 1 December 2019 в 01:31
поделиться

I suppose it's just a typo, but bool GetInt(string key) seems weird. It should be int GetInt(string key), or better yet int GetInt32(string key).

Next, Jon has already noted that boxing is required for your code to work, so this is what you do.

And finally, add a "catch-all" method to your IPropertyMap interface -- say object GetValue(string key) and then rewrite GetOrDefault to utilize this method instead of endless and error prone Type comparisons:

else
    return (T)(object)map.GetValue(key);    
3
ответ дан 1 December 2019 в 01:31
поделиться

Для справки я обнаружил другой интерфейс, в котором есть методы GetType () и GetAsObject (), которые позволяют мне интегрировать элементы этих ответов для этого:

public static T GetOrDefault<T>(this IInfosContainer container, string key, T defaultValue)
{
    //I just read p273 of C# in Depth, +1 Jon Skeet :)
    if (container == null) throw new ArgumentNullException("container");
    if (container.Exist(key))
    {
        if (container.GetType(key) != typeof(T))
            throw new ArgumentOutOfRangeException("key",
                "Key exists, but not same type as defaultValue parameter");
        else
            return (T)container.GetAsObject(key);
    }
    else
        return defaultValue;
}

( Пуристы заметят, что я не из школы «скобок для одного утверждения» ... )

0
ответ дан 1 December 2019 в 01:31
поделиться

AFAIK, некоторые попытки были сделаны в стандартной библиотеке python, но они не увенчались успехом. Подробнее см. Ограниченное выполнение .

Предупреждение

В Python 2.3 эти модули были инвалид из-за различных известных и не легко устранимые дыры в безопасности. В модули все еще описаны здесь, чтобы помощь в чтении старого кода, который использует У вас нет возможности контролировать, что такое Т. Например,

float value = map.GetOrDefault ("blah", 2.0);

не будет компилироваться, потому что Невозможно неявно преобразовать тип double в float. Существует явное преобразование (вам не хватает приведения?) Другая точка отказа - это когда желаемое значение по умолчанию равно нулю. Эти методы оставляют разработчика во власти компилятора, чтобы решить, что, по его мнению, намерен разработчик.

Если вы можете изменить интерфейс, добавьте метод GetObject. Поскольку вы используете метод расширения, я предполагаю, что вы не можете так привести к объекту, а затем к int. В любом случае измените метод, чтобы он выглядел как

public static void GetOrDefault (это карта IPropertyMap, строковый ключ, значение ref T) { если (map.Exists (ключ)) { если (typeof (T) == typeof (int)) { value = (T) (объект) map.GetInt (ключ); } значение = по умолчанию (T); // это просто мелочь, потому что я ленив, // добавить сюда настоящий код. } } и вызовите вот так

        PropertyMap map = new PropertyMap();
        float value = 2.0f;
        map.GetOrDefault("blah", ref value);

Ненавижу ref params, но я вижу в этом суть. Реестр - классический пример того, когда такой метод может быть полезен. Приведенный выше код заставляет пользователя-разработчика явно указать тип вывода и сохраняет концептуальное значение по умолчанию.

0
ответ дан 1 December 2019 в 01:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: