返回类型T不能返回null? C#泛型

时间:2011-09-07 20:50:24

标签: c# generics nullable

我有一个方法,通常从用户提供的文件路径和对象类型反序列化存储的对象。该方法工作正常,但用户提供无效文件路径时除外。我希望我的方法在这种情况下返回null,但是当我尝试返回null时,我得到一个编译错误。我试图使用可空类型,但得到编译错误。相反,我对一个对象进行类型转换并返回该对象,但它会导致运行时错误。我想知道是否有人知道允许返回null的正确方法。代码如下:

        public static T RestoreObj<T>(string datafile)
    {


        try
        {
            var fs = File.OpenRead(datafile);
            var bf = new BinaryFormatter();
            var obj = (T) bf.Deserialize(fs);
            fs.Close();
            return obj;
        }
        catch (Exception e)
        {
            MessageBox.Show("Could not load. Accepts valid *.dom files only. " + e);

            // TODO: how to do this? this will throw a runtime error, and if null returned, a compilation error
            var o = new object();
            return (T) o;
        }
    }

考虑到Eric Lippert的质量评论之后,我修改了方法,看起来就像你在下面看到的那样。使用'using'的优点是它会自动生成一个try..finally块,它将调用dispose方法(FileStream实现IDisposable,如果不是它们将是一个编译错误)。另一件好事是抛出的异常与实际发生的事情有关,而不是我上面所做的。

        public static T RestoreObj<T>(string datafile) 
    {
        using (var fs = File.OpenRead(datafile))
        {
            var bf = new BinaryFormatter();
            var obj = (T)bf.Deserialize(fs);
            return obj;
        }
    }

7 个答案:

答案 0 :(得分:20)

如果您只打算使用类,请添加where T : class约束:

public static T RestoreObj<T>(string datafile) where T : class

如果您希望反序列化结构,那么只需返回default(T)。对于引用类型,它将是null,对于结构,它将是默认值(通常为0)。正如@JMH指出的那样,default(Nullable<T>)是一个null - 包含可空。

答案 1 :(得分:11)

我会通过不首先编写代码来解决问题。

一种方法应该做一件事,做得好;您正在使用错误报告代码混合反序列化代码。

不要那样做。更好的方法是让反序列化方法抛出异常,并编写不同的代码来处理异常并向用户报告错误。

更一般地说,拥有一个吃异常然后返回虚假数据的方法是危险的。这只是在不知情的调用你的方法的代码期望得到好的数据时,就会产生问题。

虽然我们讨论的是代码质量问题,但您应该使用“using”块来确保在发生异常时关闭文件句柄。不要明确地执行fs.Close() - 而是执行using(var fs = ... )并让编译器生成关闭文件的处理。

答案 2 :(得分:4)

您可以使用default(T)代替null null作为参考类型和值类型的默认值。

答案 3 :(得分:2)

并非所有类型都可以设置为null

您必须约束T

public static T RestoreObj<T>(string datafile) where T : class

你的另一个选择(如果你没有严格使用类)是返回default(T)而不是null。

答案 4 :(得分:1)

将约束放在T上:

 public static T RestoreObj<T>(string datafile) where T : class
                                               //^^^^^^^^^^^^^^

这意味着您可以使用T调用此方法,null是一种可以T的引用类型。当Nullable<V>是值类型时,您无法调用此方法,但是当T为class R {} //Reference type! struct V {} //Value type! Xyz.RestoreObj<R>("abc"); //ok Xyz.RestoreObj<V>("abc"); //compilation error Xyz.RestoreObj<Nullable<V>>("abc"); //ok 时调用它:

{{1}}

答案 5 :(得分:1)

如果您声明这样的方法,则应该能够返回null

public static T RestoreObj<T>(string datafile) : where T class

T也可以是一个结构,不能是null。如果您将T限制为类,则必须是引用类型,并且您可以返回null

答案 6 :(得分:0)

您可以使用以下内容检查文件是否存在,并返回该类型的默认值。

            if (!File.Exists(FilePath))
            return default(T);

通过使用此功能,您将获得该类型的默认值。例如,如果给它一个'int'类型,它将返回0而不是null。