了解C#泛型和可空值类型。返回null或null

了解C#泛型和可空值类型。返回null或null,c#,generics,mono,null,nullable,C#,Generics,Mono,Null,Nullable,假设我有以下课程: public class GenericClass<T> { public T Find() { //return T if found otherwise null or Nullable<T> } } 公共类GenericClass { 公众找不到 { //如果发现为null或可为null,则返回T } } 在某个地方,我想用T和class专门化我的类,其他时候用struct。 我面临这样一个问题:如果t

假设我有以下课程:

public class GenericClass<T>
{
    public T Find()
    {
        //return T if found otherwise null or Nullable<T>
    }
}
公共类GenericClass
{
公众找不到
{
//如果发现为null或可为null,则返回T
}
}
在某个地方,我想用
T
class
专门化我的类,其他时候用
struct
。 我面临这样一个问题:如果
t
类型不被限制为
struct
,我就不能返回
Nullable

我想提供我的
Find
方法的一个实现,如果
T
同时使用
class
struct
进行专门化,该方法就可以工作。 如果
Find
失败,如果
T
是一个类,我想返回
null
,否则
null


不使用反射就可以吗?如果是,如何返回?

您可以返回
默认值(T)

对于类,这将是
null
。对于任何
Nullable
,这将是一个没有值的
Nullable
(实际上是
null

这就是说,如果将它与
struct
一起使用,而不是将
null
作为类型,那么
default(T)
将是结构的默认值


如果要使此方法对任何类或结构都能统一工作,则可能需要返回两个值—您可以在此处使用框架作为灵感,并使用TryXXX方法,即:

public bool TryFind(out T)
然后,当找不到值时,可以使用
default(T)
,并返回false。这避免了对可空类型的需要。如果要避免out参数,也可以编写此函数,返回一个
元组
或类似值,即:

public Tuple<bool, T> Find()
公共元组查找()
最后一个可能的选择是使类非泛型,然后使用一对泛型方法:

class YourClass // Non generic
{
    public T FindReference<T>() where T : class
    {
         // ...
        return null;
    }

    public Nullable<T> FindValue<T>() where T : struct
    {
         // ...
         return default(T);
    }
}
classyourclass//非泛型
{
公共T FindReference(),其中T:class
{
// ...
返回null;
}
公共可为null的FindValue(),其中T:struct
{
// ...
返回默认值(T);
}
}

请注意,您需要不同的名称,因为您不能拥有完全基于返回类型的重载方法。

我将使用以下解决方案:

public Boolean Find(out T result)
{
    // Pseudo code
    if (FindItem == true)
    {
        result = ItemFound;
        return true;
    }
    result = default(T);
    return false;
}

为什么??因为
Nullable
只接受一个结构,而上面的方法同时支持类和结构。

正如里德所说,您可以返回
default(T)

在我看来,这有一个很大的缺点:如果您的方法声明在未找到项时返回
default(T)
,则您将无法返回值类型的默认值(例如,为
Find
返回
0
通常可能是完全有效的返回值)

我宁愿买这样的东西

public class GenericClass<T>
{
    public Option<T> Find()
    {
        //return Option.Some(item) if found otherwise Option.None<T>()
    }
}

public static class Option
{
    public static Option<T> None<T>()
    {
        return new Option<T>(default(T), false);
    }

    public static Option<T> Some<T>(T value)
    {
        return new Option<T>(value, true);
    }
}

public sealed class Option<T>
{
    private readonly T m_Value;
    private readonly bool m_HasValue;

    public void Option(T value, bool hasValue)
    {
        m_Value = value;
        m_HasValue = hasValue;
    }

    public bool HasValue 
    {
        get { return m_HasValue; }
    }        

    public T Value 
    {
        get { return m_Value; }
    }
}
公共类GenericClass
{
公共选项查找()
{
//return Option.Some(项目),如果找到,则返回Option.None()
}
}
公共静态类选项
{
公共静态选项None()
{
返回新选项(默认值(T),false);
}
公共静态选项部分(T值)
{
返回新选项(值,true);
}
}
公共密封类选项
{
私有只读T m_值;
私有只读bool m_HasValue;
公共无效选项(T值,布尔值)
{
m_值=值;
m_HasValue=HasValue;
}
公共布尔值
{
获取{return m_HasValue;}
}        
公共价值
{
获取{返回m_值;}
}
}

从技术上讲,
default(T)
int
作为OP所需的通用参数提供时,将不会返回
null
,但这肯定会让您在大部分方面达到目的。确实,要得到OP想要的东西,唯一的方法就是提供两个通用实现,一个用于值类型,一个用于引用类型。@Tejs。因此,如果我需要用数字类型专门化T,我是否被迫使用out参数来实现通用解决方案?如果T是int,default会返回什么?@Tejs Yes-这就是我在最后一句话中试图说的-
default(T)
将提供一个
Nullable
,如果你使用
Nullable
作为泛型类型,thoguh.@Heisenbug如果
T
是一个
int
default(T)
将返回0。@Heisenbug我是(试图)建议将
null
用作
T
,而不是
int
用作
T
。对于
T
来说,没有约束就无法返回“null”,无论是对class,还是对struct,并返回
Nullable
+1,这个习惯用法通常被命名为
tryxxx
,因此
TryGetValue
TryFind
都是合适的。@sixtletvariables是的,您是正确的。但我还是沿用了Heisenburg使用的名称。如果返回类型为T,则不能返回T或Nullable。这实际上是在编写一种新形式的
Nullable
,它不受结构的约束-现在,如果C具有模式匹配,这将是一种方法;)