C# 如何实现可以返回类或可空结构的泛型集合查找方法?

C# 如何实现可以返回类或可空结构的泛型集合查找方法?,c#,generics,C#,Generics,我需要一个异构集合的类型化查找帮助器函数:它应该返回一个结构或类,如果找不到该项,则返回null。 下面是一个使用普通集合查找的示例,但它可以是数据库调用或其他任何形式 有没有办法用一个方法签名来实现这一点 public T GetClass<T>(string key) where T : class { object o; if (Contents.TryGetValue(key, out o)) {

我需要一个异构集合的类型化查找帮助器函数:它应该返回一个结构或类,如果找不到该项,则返回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;
    }
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;
}
我已经尝试过的:

  • 我理解通用限制不能用来消除重载的歧义。所以我不能简单地给这两个方法取相同的名字
  • 返回
    (默认)T
    不是选项,因为0是有效的int值
  • 我曾尝试使用
    作为类型进行调用,但正如前面所讨论的,
    可为null的
    不是引用类型
是否有某种方法表明我将返回一个带方框的int

有没有办法用一个方法签名来实现这一点

    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?是可空的别名可空是结构