C#泛型代码膨胀-我应该担心吗?

C#泛型代码膨胀-我应该担心吗?,c#,generics,C#,Generics,我想问一些关于泛型的问题 我试图使代码保持简单,因此我将创建一个类来处理游戏的savegame文件的加载/保存。由于游戏的每个部分都有不同的要求,我希望尽可能方便地访问: public void Load<T>(string path, out T obj) { BinaryFormatter bf = new BinaryFormatter(); using (FileStream file = File.Open(Application.persistentDat

我想问一些关于泛型的问题

我试图使代码保持简单,因此我将创建一个类来处理游戏的savegame文件的加载/保存。由于游戏的每个部分都有不同的要求,我希望尽可能方便地访问:

public void Load<T>(string path, out T obj)
{
    BinaryFormatter bf = new BinaryFormatter();
    using (FileStream file = File.Open(Application.persistentDataPath + path, FileMode.Open))
    {
        obj = (T)bf.Deserialize(file);
    }
}
另一种方法是让Load函数返回对象,然后将其转换为TurnData类型

TurnData x = (TurnData)s.Load("test.txt");
我对C不太了解。例如,如果打开文件时出现错误,我假设使用(…){…}的
中的代码不会执行?如果有人能证实这一点,那就太好了。我看到的示例代码没有任何错误处理,这对我来说很奇怪,所以我添加了使用

因此,在这个二级版本中,函数返回对象而不是使用out参数,需要更复杂的代码进行错误检查,并可能返回null?看起来不太好


所以真正的问题是。。。我可以使用这里的下一个版本吗?或者由于使用泛型,我应该考虑哪些问题?

使用
语句与错误处理无关。使用
File.Open
方法,您可以期望得到您将发现的异常。通过将using语句包装在
try/cath
结构中,可以避免程序因任何此类异常而突然停止,如下所示:

public T Load<T>(string path)
{
    T obj = default(T);
    var bf = new BinaryFormatter();
    try
    {
        using (var file = File.Open(Application.persistentDataPath + path, FileMode.Open))
        {
            obj = (T)bf.Deserialize(file);
        }
    }
    catch(Exception exception)
    {
        // Log the exception
    }
    return obj;

}


进行上述更改可以使您的方法更容易通过单元测试进行测试,并且更可靠,因为您可以在方法开始之前进行一些先决条件检查。如果您传递了一个空的
路径
,会发生什么?如果传递的是空格式化程序,会发生什么?等等。

没有通用代码膨胀-代码被重用。但是,对于值类型,CLR将为每种类型生成一个单独的方法。看见
.

使用
块只是简化版的
try{}最终{//will dispose dispose-dispose-object}
基本上是调用对象的
dispose()
方法,即使块中的代码抛出异常。我不明白为什么要使用泛型编写代码。为什么
Foo-Foo;加载(路径、输出foo)在任何方面都优于
Foo-Foo=(Foo)Load(path)?后者对我来说似乎更清晰,更短更简单。你的建议很有价值,你应该考虑去做。您将不得不以任何一种方式编写错误处理。@EricLippert,这不是
out
变量的问题吗?我真的不明白为什么输出会让它更可读?这段代码没有编译:CS0403无法将null转换为类型参数“t”,因为它可能是不可为null的值类型。考虑使用“默认(t)”代替。@ PavultupSyn你是非常该死的正确!我刚刚纠正了它。Thanks@StuartLC非常感谢您的评论。Pavel还指出:)上面的示例代码违反了几个C#最佳实践:不要抛出NullReferenceException。有一种异常类型专门用于此情况:ArgumentNullException请参阅:。此外,请不要捕捉一般例外情况,请参阅:@DaveM,谢谢您的评论。关于第一点,我完全同意你的看法。我的错…事实上,我们从未为空参数值抛出NullReferenceException。这就是我刚刚纠正它的原因。但是关于第二点,我有不同的看法。特别是,如果您不希望程序意外崩溃,无论何时抛出可能的异常,您都必须捕获所有异常并采取适当的行动。我从这种情况中排除了一些异常,比如表示方法使用不当的空参数异常。我知道我已经读过了,这就是为什么我明确指出Mono正在使用的原因,而这并不一定适用
public T Load<T>(string path)
{
    T obj = default(T);
    var bf = new BinaryFormatter();
    try
    {
        using (var file = File.Open(Application.persistentDataPath + path, FileMode.Open))
        {
            obj = (T)bf.Deserialize(file);
        }
    }
    catch(Exception exception)
    {
        // Log the exception
    }
    return obj;

}
public T Load<T>(string path, IFormatter formatter)
{
    if(path ==null) throw new ArgumentNullException(nameof(path));
    if(formatter == null) throw new ArgumentNullException(nameof(formatter));

    T obj = default(T);
    try
    {
        using (var file = File.Open(path, FileMode.Open))
        {
            obj = (T)formatter.Deserialize(file);
        }
    }
    catch(Exception exception)
    {
        // Log the exception
    }
    return obj;   
}
var path = Path.Combine(Application.persistentDataPath, "test.txt");
var binaryFormatter = new BinaryFormatter();
var x = s.Load(path, binaryFormatter);