如何使用 C# 泛型来简化对 WinRT 设置的访问?

How to use C# generics to simplify access to WinRT settings?

在 WinRT 中,设置存储为对象,这意味着您最终需要进行大量转换才能恢复到您想要的类型。由于这似乎映射到将泛型添加到 C# 的原因之一,我一直在努力简化我的代码,以便我可以做类似的事情:

    public string LastRunVersion
    {
        get
        {
            return GetLocalSettingsValue<String>("LastRunVersion", null);
        }

        set
        {
            SetLocalSettingsValue("LastRunVersion", value);
        }
    }

我遇到的问题是 SetLocalSettingsValue 的签名。我试过了:

private T GetLocalSettingsValue<T>(string tag, T defaultValue) where T:Object

但 Object 是不允许的,因为它不是有效的约束。我知道我只存储布尔值和字符串,所以我尝试了:

private T GetLocalSettingsValue<T>(string tag, T defaultValue) where T:String, bool

但是编译器说 "A type used as a constraint must be an interface, a non-sealed class or a type parameter".

我需要如何处理定义才能使用字符串和布尔值?

谢谢。

正如 Sriram 所建议的那样,实施两种不同的方法似乎是解决当前问题的最简单的解决方案。也就是说,您的通用方法是可行的,有先例,并且将使将来扩展代码变得更加容易。

事实上,您的尝试几乎是正确的。最主要的是你实际上根本不需要约束。没有它,方法声明也很好,虽然你没有显示方法主体,但只要你需要做的就是将一些对象引用转换为类型 T,就可以了:

private T GetLocalSettingsValue<T>(string tag, T defaultValue)
{
    object value;

    // initialize/retrieve the value somehow

    // Check for value present, return default if missing, cast otherwise
    return value != null ? (T)value : defaultValue;
}

事实上,由于您传递的是默认值,类型推断在某些情况下允许您省略类型参数。例如:

public string LastRunVersion
{
    get { return GetLocalSettingsValue("LastRunVersion", (string)null); }
}

如果你有一个非空的默认值,上面的内容会更有趣。 :) 对于 null 值,您必须将其转换为 string 以便编译器知道正确的类型是什么,这实际上与仅提供类型参数相同。但是,如果您传递的是 string 文字或 string 变量的值,则类型将很清楚,并且根本不需要提供类型名称(甚至不需要作为强制转换) .

更有趣的是bool场景:

public string LastRunVersion
{
    get { return GetLocalSettingsValue("SomeBooleanSetting", false); }
}

此处,字面量具有明确的类型,因此您无需以任何形式提供类型名称。

最后,请注意 C# 确实有 default 类型值的概念。如果您想支持非空、非零默认值,那么您当前的方法很好。但是,如果您的默认设置总是像 nullfalse0(例如,对于 int,您是否需要存储类似的东西) ,那么你根本不需要默认参数:

private T GetLocalSettingsValue<T>(string tag)
{
    object value;

    // initialize/retrieve the value somehow

    // Check for value present, return default if missing, cast otherwise
    return value != null ? (T)value : default(T);
}

任何引用类型都将使用 null 作为默认值。对于值类型,如果您使用无参数构造函数创建实例(所有值类型都有无参数构造函数),您将获得任何值。数字类型都默认为它们的版本 0,bool 默认为 false,等等

当然,在那种情况下,您将始终必须提供类型参数,因为没有任何参数可以从中推断出类型参数。