C# 如何实现可以返回类或可空结构的泛型集合查找方法?
我需要一个异构集合的类型化查找帮助器函数:它应该返回一个结构或类,如果找不到该项,则返回null。 下面是一个使用普通集合查找的示例,但它可以是数据库调用或其他任何形式 有没有办法用一个方法签名来实现这一点C# 如何实现可以返回类或可空结构的泛型集合查找方法?,c#,generics,C#,Generics,我需要一个异构集合的类型化查找帮助器函数:它应该返回一个结构或类,如果找不到该项,则返回null。 下面是一个使用普通集合查找的示例,但它可以是数据库调用或其他任何形式 有没有办法用一个方法签名来实现这一点 public T GetClass<T>(string key) where T : class { object o; if (Contents.TryGetValue(key, out o)) {
public T GetClass<T>(string key) where T : class
{
object o;
if (Contents.TryGetValue(key, out o))
{
return o as T;
}
return null;
}
public T? GetStruct<T>(string key) where T : struct
{
object o;
if (Contents.TryGetValue(key, out o))
{
if (o is T)
{
return (T?) o;
}
}
return null;
}
public T GetClass(字符串键),其中T:class
{
对象o;
if(Contents.TryGetValue(key,out o))
{
返回o作为T;
}
返回null;
}
公共电话?GetStruct(字符串键),其中T:struct
{
对象o;
if(Contents.TryGetValue(key,out o))
{
if(o是T)
{
返回(T?)o;
}
}
返回null;
}
我已经尝试过的:
- 我理解通用限制不能用来消除重载的歧义。所以我不能简单地给这两个方法取相同的名字
- 返回
不是选项,因为0是有效的int值(默认)T
- 我曾尝试使用
作为类型进行调用,但正如前面所讨论的,
不是引用类型可为null的
public T GetClass<T>(string key) where T : class
{
object o;
if (Contents.TryGetValue(key, out o))
{
return o as T;
}
return null;
}
public T? GetStruct<T>(string key) where T : struct
{
object o;
if (Contents.TryGetValue(key, out o))
{
if (o is T)
{
return (T?) o;
}
}
return null;
}
有一种(真正可怕的)方法可以使用可选参数来实现,这样调用代码在两种情况下看起来都一样。不过很恶心
选项:
- 返回一个
,而不是使用空值元组
- 使用
参数(如out
等)int.TryParse
- 使用不同的方法名称
null
成为有效的“已找到”结果,这有时会很有用。或者你可以保证它永远不会被退回
如果你真的想使用空值,我会选择最后一个选项。我相信它会让你的代码更清晰。国际海事组织,重载应该只在方法使用不同的参数执行完全相同的操作时使用,而在一种情况下返回
Nullable
作为返回类型,而在另一种情况下返回T
作为返回类型,这两种情况实际上不能这样看。以下方法适用于类和Nullable结构:
public static T GetValue<T>(string key)
{
object o;
if (Contents.TryGetValue(key, out o))
{
if (o is T)
{
return (T)o;
}
}
return default(T);
}
publicstatict GetValue(字符串键)
{
对象o;
if(Contents.TryGetValue(key,out o))
{
if(o是T)
{
返回(T)o;
}
}
返回默认值(T);
}
用法:
int?result1=GetValue(“someInt”);
string result2=GetValue(“someString”);
请注意,
?
是泛型类型参数的一部分,而不是由返回类型上的方法定义的。这应该完全满足您的需要。如果请求的类型是可为空的类型,请在强制转换之前检查基础类型
public static T GetValue<T>(string key)
{
object o;
if (Contents.TryGetValue(key, out o))
{
if (o is T || Nullable.GetUnderlyingType(typeof(T)) == o.GetType())
{
return (T)o;
}
}
return default(T);
}
publicstatict GetValue(字符串键)
{
对象o;
if(Contents.TryGetValue(key,out o))
{
如果(o是T | |可为null的。GetUnderlyingType(typeof(T))==o.GetType()
{
返回(T)o;
}
}
返回默认值(T);
}
我的测试代码:
Contents.Add("a string", "string value");
Contents.Add("an integer", 1);
Contents.Add("a nullable integer", new Nullable<int>(2));
// Get objects as the type we originally used.
Debug.WriteLine(string.Format("GetValue<string>(\"a string\") = {0}", GetValue<string>("a string")));
Debug.WriteLine(string.Format("GetValue<int>(\"an integer\") = {0}", GetValue<int>("an integer")));
Debug.WriteLine(string.Format("GetValue<int?>(\"a nullable integer\") = {0}", GetValue<int?>("a nullable integer")));
// Get objects as base class object.
Debug.WriteLine(string.Format("GetValue<object>(\"a string\") = {0}", GetValue<object>("a string")));
Debug.WriteLine(string.Format("GetValue<object>(\"an integer\") = {0}", GetValue<object>("an integer")));
Debug.WriteLine(string.Format("GetValue<object>(\"a nullable integer\") = {0}", GetValue<object>("a nullable integer")));
// Get the ints as the other type.
Debug.WriteLine(string.Format("GetValue<int?>(\"an integer\") = {0}", GetValue<int?>("an integer")));
Debug.WriteLine(string.Format("GetValue<int>(\"a nullable integer\") = {0}", GetValue<int>("a nullable integer")));
// Attempt to get as a struct that it's not, should return default value.
Debug.WriteLine(string.Format("GetValue<double>(\"a string\") = {0}", GetValue<double>("a string")));
// Attempt to get as a nullable struct that it's not, or as a class that it's not, should return null.
Debug.WriteLine(string.Format("GetValue<double?>(\"a string\") = {0}", GetValue<double?>("a string")));
Debug.WriteLine(string.Format("GetValue<StringBuilder>(\"a string\") = {0}", GetValue<StringBuilder>("a string")));
Contents.Add(“字符串”、“字符串值”);
内容。添加(“一个整数”,1);
添加(“一个可为空的整数”,新的可为空(2));
//以我们最初使用的类型获取对象。
Debug.WriteLine(string.Format(“GetValue(\“a string\”)={0}),GetValue(“a string”));
Debug.WriteLine(string.Format(“GetValue(\“一个整数”)={0},GetValue(“一个整数”));
Debug.WriteLine(string.Format(“GetValue(\“可为空的整数\”)={0}”,GetValue(“可为空的整数”));
//获取对象作为基类对象。
Debug.WriteLine(string.Format(“GetValue(\“a string\”)={0}),GetValue(“a string”));
Debug.WriteLine(string.Format(“GetValue(\“一个整数”)={0},GetValue(“一个整数”));
Debug.WriteLine(string.Format(“GetValue(\“可为空的整数\”)={0}”,GetValue(“可为空的整数”));
//将int作为其他类型获取。
Debug.WriteLine(string.Format(“GetValue(\“一个整数”)={0},GetValue(“一个整数”));
Debug.WriteLine(string.Format(“GetValue(\“可为空的整数\”)={0}”,GetValue(“可为空的整数”));
//尝试以非结构形式获取时,应返回默认值。
Debug.WriteLine(string.Format(“GetValue(\“a string\”)={0}),GetValue(“a string”));
//尝试作为一个可为null的结构获取它不是,或者作为一个类获取它不是,应该返回null。
Debug.WriteLine(string.Format(“GetValue(\“a string\”)={0}),GetValue(“a string”));
Debug.WriteLine(string.Format(“GetValue(\“a string\”)={0}),GetValue(“a string”));
结果:
GetValue<string>("a string") = string value
GetValue<int>("an integer") = 1
GetValue<int?>("a nullable integer") = 2
GetValue<object>("a string") = string value
GetValue<object>("an integer") = 1
GetValue<object>("a nullable integer") = 2
GetValue<int?>("an integer") = 1
GetValue<int>("a nullable integer") = 2
GetValue<double>("a string") = 0
GetValue<double?>("a string") =
GetValue<StringBuilder>("a string") =
GetValue(“字符串”)=字符串值
GetValue(“一个整数”)=1
GetValue(“可为空的整数”)=2
GetValue(“字符串”)=字符串值
GetValue(“一个整数”)=1
GetValue(“可为空的整数”)=2
GetValue(“一个整数”)=1
GetValue(“可为空的整数”)=2
GetValue(“字符串”)=0
GetValue(“字符串”)=
GetValue(“字符串”)=
I有一半喜欢这样,但它允许您将其称为GetClass
,并为“foundwithvalue 0”和“notfound”返回0。实际上,您可能会在示例用法中意外地漏掉第二个?
,并得到一个相当微妙的bug。(result1
永远不会为空,但您会期望它为空)我认为int的默认值是多少?是null,但是如果您正在查找的值是一个常规int,该怎么办:我认为(o是int?)将失败bc int?不是int。@akatakritos:Jon指出,您也可以调用GetValue
,它将返回0
,而不是null
。当然,可以向该方法添加运行时检查以防止出现这种情况。我的代码也适用于常规整数,因为(object)42是整数?
是真的。akatakritos:int?是可空的别名可空是结构