如何使用 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
类型值的概念。如果您想支持非空、非零默认值,那么您当前的方法很好。但是,如果您的默认设置总是像 null
、false
或 0
(例如,对于 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
,等等
当然,在那种情况下,您将始终必须提供类型参数,因为没有任何参数可以从中推断出类型参数。
在 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
类型值的概念。如果您想支持非空、非零默认值,那么您当前的方法很好。但是,如果您的默认设置总是像 null
、false
或 0
(例如,对于 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
,等等
当然,在那种情况下,您将始终必须提供类型参数,因为没有任何参数可以从中推断出类型参数。