我想问一些关于泛型的事情。
我正在尝试保持代码简单,因此我将创建一个单独的类来处理游戏的存储游戏文件的加载/保存。由于游戏的每个部分都有不同的要求,我希望尽可能方便地访问:
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);
}
}
现在我可以用一个简单的
来调用它TurnData x; s.Load("test.txt", out x);
另一种方法是使Load函数返回对象,然后将其转换为TurnData类型。
TurnData x = (TurnData)s.Load("test.txt");
我对C#了解不多。我假设如果例如打开文件时出错,则using(...) { ... }
内的代码不会被执行?如果有人可以证实这很好。我看到的示例代码没有任何错误处理,这对我来说似乎很奇怪,所以我添加了使用?
所以在这个函数返回对象而不是使用out参数的二级版本中,需要更复杂的代码进行错误检查,并且可能返回null?它看起来并不好。
所以真正的问题是......我可以使用我在这里的下一个版本,还是因为使用泛型而我应该有这些问题?
答案 0 :(得分:4)
reference types没有通用代码膨胀 - 代码被重用。但是,对于值类型,CLR将为每种类型生成单独的方法。看到 .NET Generics and Code Bloat
答案 1 :(得分:3)
using
语句与错误处理无关。使用File.Open
方法,您可以获得here找到的例外情况。通过将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;
}
基本上,您尝试打开路径中指定的文件。如果失败,您只需记录失败并从函数中返回null
。
关于 using
语句,它提供了
一种方便的语法,可确保正确使用IDisposable 对象。
您可以更全面地阅读here
作为关于方法签名的旁注,我会发表一些评论。考虑以下方法体,并发现与上述方法的差异。
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);
进行上述更改后,您可以通过单元测试更轻松地对方法进行测试,并且更加可靠,因为您在方法的肉和土豆之前进行了一些前置条件检查。如果您通过了空path
会发生什么?如果您通过了null格式化程序会发生什么?等...