Для быстрого и легкого использования я написал эту функцию некоторое время назад. Он возвращает разницу между двумя датами в хорошем формате. Не стесняйтесь использовать его (проверено на webkit).
/**
* Function to print date diffs.
*
* @param {Date} fromDate: The valid start date
* @param {Date} toDate: The end date. Can be null (if so the function uses "now").
* @param {Number} levels: The number of details you want to get out (1="in 2 Months",2="in 2 Months, 20 Days",...)
* @param {Boolean} prefix: adds "in" or "ago" to the return string
* @return {String} Diffrence between the two dates.
*/
function getNiceTime(fromDate, toDate, levels, prefix){
var lang = {
"date.past": "{0} ago",
"date.future": "in {0}",
"date.now": "now",
"date.year": "{0} year",
"date.years": "{0} years",
"date.years.prefixed": "{0} years",
"date.month": "{0} month",
"date.months": "{0} months",
"date.months.prefixed": "{0} months",
"date.day": "{0} day",
"date.days": "{0} days",
"date.days.prefixed": "{0} days",
"date.hour": "{0} hour",
"date.hours": "{0} hours",
"date.hours.prefixed": "{0} hours",
"date.minute": "{0} minute",
"date.minutes": "{0} minutes",
"date.minutes.prefixed": "{0} minutes",
"date.second": "{0} second",
"date.seconds": "{0} seconds",
"date.seconds.prefixed": "{0} seconds",
},
langFn = function(id,params){
var returnValue = lang[id] || "";
if(params){
for(var i=0;i<params.length;i++){
returnValue = returnValue.replace("{"+i+"}",params[i]);
}
}
return returnValue;
},
toDate = toDate ? toDate : new Date(),
diff = fromDate - toDate,
past = diff < 0 ? true : false,
diff = diff < 0 ? diff * -1 : diff,
date = new Date(new Date(1970,0,1,0).getTime()+diff),
returnString = '',
count = 0,
years = (date.getFullYear() - 1970);
if(years > 0){
var langSingle = "date.year" + (prefix ? "" : ""),
langMultiple = "date.years" + (prefix ? ".prefixed" : "");
returnString += (count > 0 ? ', ' : '') + (years > 1 ? langFn(langMultiple,[years]) : langFn(langSingle,[years]));
count ++;
}
var months = date.getMonth();
if(count < levels && months > 0){
var langSingle = "date.month" + (prefix ? "" : ""),
langMultiple = "date.months" + (prefix ? ".prefixed" : "");
returnString += (count > 0 ? ', ' : '') + (months > 1 ? langFn(langMultiple,[months]) : langFn(langSingle,[months]));
count ++;
} else {
if(count > 0)
count = 99;
}
var days = date.getDate() - 1;
if(count < levels && days > 0){
var langSingle = "date.day" + (prefix ? "" : ""),
langMultiple = "date.days" + (prefix ? ".prefixed" : "");
returnString += (count > 0 ? ', ' : '') + (days > 1 ? langFn(langMultiple,[days]) : langFn(langSingle,[days]));
count ++;
} else {
if(count > 0)
count = 99;
}
var hours = date.getHours();
if(count < levels && hours > 0){
var langSingle = "date.hour" + (prefix ? "" : ""),
langMultiple = "date.hours" + (prefix ? ".prefixed" : "");
returnString += (count > 0 ? ', ' : '') + (hours > 1 ? langFn(langMultiple,[hours]) : langFn(langSingle,[hours]));
count ++;
} else {
if(count > 0)
count = 99;
}
var minutes = date.getMinutes();
if(count < levels && minutes > 0){
var langSingle = "date.minute" + (prefix ? "" : ""),
langMultiple = "date.minutes" + (prefix ? ".prefixed" : "");
returnString += (count > 0 ? ', ' : '') + (minutes > 1 ? langFn(langMultiple,[minutes]) : langFn(langSingle,[minutes]));
count ++;
} else {
if(count > 0)
count = 99;
}
var seconds = date.getSeconds();
if(count < levels && seconds > 0){
var langSingle = "date.second" + (prefix ? "" : ""),
langMultiple = "date.seconds" + (prefix ? ".prefixed" : "");
returnString += (count > 0 ? ', ' : '') + (seconds > 1 ? langFn(langMultiple,[seconds]) : langFn(langSingle,[seconds]));
count ++;
} else {
if(count > 0)
count = 99;
}
if(prefix){
if(returnString == ""){
returnString = langFn("date.now");
} else if(past)
returnString = langFn("date.past",[returnString]);
else
returnString = langFn("date.future",[returnString]);
}
return returnString;
}
В контексте метода, который открывает файл, я использовал бы оператор использования по сравнению с выгодой попытки. Оператор использования гарантирует, чтобы Расположили, назван, если исключение происходит.
using (FileStream fs = new FileStream(file, FileMode.Open))
{
//do stuff
}
делает то же самое как:
FileStream fs;
try
{
fs = new FileStream(file, FileMode.Open);
//do Stuff
}
finally
{
if(fs!=null)
fs.Dispose();
}
Теперь, когда у нас есть лямбды и вывод типа и некоторый другой материал, существует идиома, которая распространена в других языках, который теперь имеет много смысла в C#. Ваш пример был об открытии файла, выполнении чего-то к нему и затем закрытии его. Ну, теперь, можно сделать вспомогательный метод, который открывает файл и также заботится о проверке закрыться / располагают / моются, но обращается к лямбде, которую Вы предусматриваете, "действительно наполняют" часть. Это поможет, Вы получить сложную попытку/выгоду/наконец располагаете/очистка материал прямо в одном месте и затем используете его много раз.
Вот пример:
public static void ProcessFile(string filePath, Action<File> fileProcessor)
{
File openFile = null;
try
{
openFile = File.Open(filePath); // I'm making this up ... point is you are acquiring a resource that needs to be cleaned up after.
fileProcessor(openFile);
}
finally
{
openFile.Close(); // Or dispose, or whatever.
}
}
Теперь, вызывающие стороны этого метода не должны волноваться о том, как открыть файл, или близко / избавляются от него. Они могут сделать что-то вроде этого:
Helpers.ProcessFile("C://somefile.txt", f =>
{
while(var text = f.ReadLine())
{
Console.WriteLine(text);
}
});
Это - вопрос о стиле, но для меня я пытаюсь никогда не иметь больше чем один уровень вложения попытки/выгоды/наконец в отдельном методе. В точке Вы поражаете вложенную попытку, Вы почти наверняка нарушили 1 функцию = 1 операционный принципал и должны использовать второй метод.
Зависит от того, что Вы пытаетесь сделать, но в большинстве случаев, вложенная попытка/выгоды является знаком сверхкомплексной функции (или программиста, который не вполне знает, как работают исключения!).
В случае открытого файла, я использовал бы держателя IDisposable и пункт использования, и тем самым воздержался бы от потребности любой явной попытки/выгоды.
Большую часть времени я разбил бы вложенные блоки попытки/выгоды в функции. Но я иногда писал код, чтобы поймать и зарегистрировать все неперехваченные исключения, выданные моим приложением. Но что, если регистрирующийся код перестал работать? Таким образом, у меня есть еще одна попытка/выгода вокруг этого только, чтобы препятствовать тому, чтобы пользователь видел диалоговое окно необработанного исключения.NET по умолчанию. Но даже этот код мог очень легко быть пересмотрен в функции вместо вложенных блоков попытки/выгоды.
try
{
try
{
DoEverything();
}
catch (Exception ex)
{
// Log the exception here
}
}
catch (Exception ex)
{
// Wow, even the log is broken ...
}