[Request-for-help] API for temp file.
От: Sinix  
Дата: 24.09.16 09:17
Оценка:
Long story short: у нас в CodeJam среди кучи других полезняшек есть микро-хелпер для работы с временными файлами: завёл-поработал-оноавтоматомгрохнулось.

Выглядит как-то так:
            using (var tempFile = TempData.CreateFile())
            {
                DoSomethingWith(tempFile.Path);
            }
            // file is deleted for now


И всё вроде было отлично, пока не пришёл уважаемый Vasiliy2
Автор: Vasiliy2
Дата: 22.09.16
и не задал нехороший вопрос: а что нужно делать, если временный файл удалить не получается? С контрольным аргументом: куча последовательных вызовов выкушает всё место и наступит полная печаль

Текущее поведение вроде как соответствует FDG (ага, нет явных доводов за любую позицию — обращайся к FDG) и проглатывает исключения, связанные с ошибками удаления файла. Молча проглатывает. Почему так — см вот эту
Автор: Sinix
Дата: 22.09.16
кучу цитат. Если коротко — сигналить "всё пропало, шеф" при диспозе не очень хорошо, т.к. это может привести к ещё худшим последствиям.

И теперь собственно вопрос: а как быть-то? Основные варианты собраны вот тут, кому лень открывать —
  скопировал
    public class TempDataUseCases
    {
        public void CaseA_NoHelpers()
        {
            // weird one.

            var fileName = "1.txt";
            Exception deletedEx = null;
            try
            {
                File.Create(fileName).Close();

                Process(fileName);
            }
            finally
            {
                try
                {
                    File.Delete(fileName); // we do expect this will throw.
                }
                catch (Exception ex)
                {
                    deletedEx = ex;
                }
            }

            if (deletedEx != null)
            {
                HandleDeleteFailure(fileName, deletedEx);
            }
        }

        public void CaseB_LetItCrash()
        {
            // ok if failure is handled by caller
            using (var tempFile = TempData.CreateFile(throwOnDisposeFailure: true))
            {
                Process(tempFile.FileName);
            } // dispose will throw
        }

        public void CaseC_LetItCrashHandle()
        {
            // BAD BAD BAD: we need to store fileName somewhere.
            string fileName = null;
            try
            {
                using (var tempFile = TempData.CreateFile(throwOnDisposeFailure: true))
                {
                    fileName = tempFile.FileName;
                    Process(tempFile.FileName);
                }
            }
            catch (Exception ex) when (fileName != null) // HACK. Will not work on C#5 or below.
            {
                HandleDeleteFailure(fileName, ex);
            }
        }

        public void CaseD_TryDelete()
        {
            using (var tempFile = TempData.CreateFile())
            {
                Process(tempFile.FileName);

                if (!tempFile.TryClose())
                {
                    HandleDeleteFailure(tempFile.FileName, null); // no exception info available.
                }
            }
        }

        public void CaseE_EnsureDeleted()
        {
            // kinda ok
            using (var tempFile = TempData.CreateFile())
            {
                Process(tempFile.FileName);

                try
                {
                    tempFile.EnsureDelete();
                }
                catch (Exception ex)
                {
                    HandleDeleteFailure(tempFile.FileName, ex);
                }
            }
        }

        public void CaseF_ManualDelete()
        {
            // kinda ok
            using (var tempFile = TempData.CreateFile())
            {
                Process(tempFile.FileName);

                try
                {
                    File.Delete(tempFile.FileName);
                }
                catch (Exception ex)
                {
                    HandleDeleteFailure(tempFile.FileName, ex);
                }
            }
        }


        public void CaseG_Fallback()
        {
            // The best?
            using (var tempFile = TempData.CreateFile(
                (f, ex) => HandleDeleteFailure(f.FileName, ex)))
            {
                Process(tempFile.FileName);
            }
        }

        private void Process(string tempFile) { }

        private void HandleDeleteFailure(string fileName, Exception exception) { }
    }

    // Stub implementation. Unusable by design.
    public class TempData : IDisposable
    {
        public static TempData CreateFile() => new TempData();
        public static TempData CreateFile(bool throwOnDisposeFailure) => new TempData();
        public static TempData CreateFile(Action<TempData, Exception> deleteFallback) => new TempData();

        public string FileName => null;

        public void EnsureDelete()
        {
            throw new IOException("Cannot delete the file.");
        }

        public bool TryClose() => false;

        public void Dispose()
        {
            // ok or throw
        }
    }


Варианты и предложения приветствуются

UPD. И да, FileOptions.DeleteOnClose подходит не всегда. Чтоб не спорить — у нас точно такой же хелпер есть для директорий. Что с ними делать будем? ; )
Отредактировано 25.09.2016 18:42 Sinix . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.