Ласкаво просимо до dev.net.ua Увійти | Приєднатися | Допомога | Увійти Live ID
в Пошук

usarskyy

String vs FileInfo як аргумент методу

Натрапив сьогодні на збірку лінків про всякі цікаві штуки (хочу сказати, автор справді знайшов цікаві теми). Одна з обговорюваних тем (прямий лінк) - як краще передавати шлях до файлу в метод: через FileInfo чи через string?

Для тих хто не хоче перечитувати всі коментарі в темі на StackOverflow, постараюсь стисло передати всю їх суть:

  1. як "золоту середину" було запропоновано рішення з 2 методами один з яких приймає string, а інший FileInfo
  2. особливо оптимістично налаштовані вирішили, що використання Stream має вирішити  всі проблеми
  3. тільки один з учасників читає MSDN :) саме він і запостив, на мою думку, найбільш інформативний коментар ("The difference is primarily that there is a little bit of checking going on; the FileInfo constructor does some checking for a null or clearly invalid parameter...")

Тепер декілька слів по кожному з пунктів:

  1. Створювати два методи (які будуть практично ідентичні!) тільки для того щоб всі залишились задоволеними - це якось тупо... і "попахує" добре відомою американською політкоректністю :)
  2. у випадку передачі Stream як аргумента без гострої на те необхідності - на кодревю зразу ж потрібно перевіряти справку від психіатра
  3. а от почитати MSDN + подивитись Reflector-ом всередину конструктора FileInfo і аргументувати його (не)використання - це досить-таки непогана ідея!

І так, ось що можна побачити всередині конструктора:

[
code language="C#"]
        public FileInfo(string fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName");
            }
            base.OriginalPath = fileName;
            string fullPathInternal = Path.GetFullPathInternal(fileName);
            new FileIOPermission(FileIOPermissionAccess.Read, new string[] {fullPathInternal}, false, false).Demand();
            this._name = Path.GetFileName(fileName);
            base.FullPath = fullPathInternal;
        }
[/
code]

Коротке пояснення коду:

  • спочатку йде перевірка на null (до речі, в когось є ідеї чому "fileInfo" не перевіряється на пусту строку?) - це ясно
  • всередині "Path.GetFullPathInternal(fileName)" проходить валідація шляху до файлу + отримання повного шляху в разі, якщо "fileName" - це відносний шлях  (ага! а от перевірка на пусту строку :) )
  • перевірка прав на читання - на мою думку, одна з осносних причин чому варто використовувати FileInfo
  • виклик "Path.GetFileName(fileName)" просто перевіряє шлях до файлу на invalid-символи

Як бачимо, нічого надзвичайного :)
Переваги в порівнянні з методом який використовує
string-аргумент очевидні:
- "халявна" перевірка шляху на валідність
- перевірка прав перед читанням (про це постійно забувають), а значить можна спростити код обробки помилок в процесі самого читання

Недоліки:
- виклик методу з
kernel32 для отрмання повного шляху і перевірка прав доступу займає якийсь час, хоча не думаю що це критично

FYI:
Атрибути і вся інша інформація підгрузиться тільки в момент коли це справді необхідно, тому про додаткові витрати ресурсів хвилюватись не варто.


Як на мене, я бачу більше "плюсів" при використанні
FileInfo - додаткові халявні перевірки (в межах розумного) ніколи не бувають лишніми :)

The end

P.S.: Якщо хтось бажає додати "за/проти" кожного з методів, розказати байку про їх використання або просто висказати своє "+1" - прошу в коменти

Опубліковані Friday, May 29, 2009 10:04 PM від usarskyy

Коментарі

 

akrakovetsky сказав:

Якщо FileInfo - краще рішення, чому ж тоді весь .net framework використовує strings в якості path? Причому в одних випадках відносні шляхи, в інших - абсолютні?

Я думаю, що метод (клас) не повинен думати за валідність path, про це має думати метод (клас, програма), яка передає параметр. До того ж, яка різниця, чи видасть exception клас FileInfo чи метод при спробі прочитати шлях (хоча це вже залежить від того, як ви ловите exceptions)?

Ще один мінус в FileInfo (хай і не великий) - потрібно підключати System.IO namespace.

НУ і суб'єктивно з строкою працювати легше (Sever.MapPath(), AppDomain.CurrentDomain.BaseDirecrory на крайній випадок).

А в цілому цікаве порівняння :)

May 30, 2009 2:10 AM
 

usarskyy сказав:

>> Якщо FileInfo - краще рішення, чому ж тоді весь .net framework використовує strings в якості path?

1) обговорення і мій пост - не про фреймворки (тут моя вина, що я не вказав це з самого початку)

2) так, є різниця між дизайном фрейморка і звичайного application (хто знає як правильно перекласти?)

3) не весь фреймворк, а тільки конструктори FileStream, StreamReader + можливо ще щось.

Зроблено це для того, щоб зменшити залежності між базовими типами (див. Framework Design Guidelines, нажаль номер сторінки не згадаю)

>> Причому в одних випадках відносні шляхи, в інших - абсолютні?

1) кожен раз при створенні FileInfo/FileStream/StreamReader типу йде перевірка чи це прямий, чи відносний шлях. А потім викликається метод з kernel32 який дає повний шлях.

Відносні шляхи - це тільки для девелоперів, робота з файлами проходить тільки по абсолютних шляхах

2) наскільки памятаю, відносні шляхи, в більшості, використовуються в ASP.NET. Для Win-app це не дуже характерно (хоча тут залежить від самого application)

>> Я думаю, що метод (клас) не повинен думати за валідність path, про це має думати метод (клас, програма), яка передає параметр

1) contract programming :)

2) так метод який отримує FileInfo і не думає, про це уже потурбувався caller (переклад?) при створенні інстансу FileInfo. Так що все "cool" :)

Якщо я неправильно зрозумів ваш аргумент - прошу пояснити детальніше

>> До того ж, яка різниця, чи видасть exception клас FileInfo чи метод при спробі прочитати шлях (хоча це вже залежить від того, як ви ловите exceptions)?

1) Як я уже сказав, перевірка проходить без нашої участі і нам не потрібно писати додаткових if-ів (економія коду & спрощення логіки) + присутня перевірка прав про яку завжди забувають

2) Різниця в місці обробки exception досить таки суттєва. Наприклад, ми пишемо програму яка проходить по текстовому файлу і вибирає ТІЛЬКИ символи "А".

За вашим сценарієм я маю створити файл для запису і відкрити файл на читання. На останньому кроці генериться Access Denied exception і логіка його обробки МАЄ включати закриття/видалення першого файлу + re-throw

Якщо йти по мому шляху, то я отримаю помилку ще ДО початку основної роботи і зможу її відповідно обробити (значить, не потрібно писати додатковий catch)

>> Ще один мінус в FileInfo (хай і не великий) - потрібно підключати System.IO namespace.

+1 рядок проти можливості зекономити 4-6 рядків тільки на if-ах - "зачем платить больше?" :)

>> НУ і суб'єктивно з строкою працювати легше (Sever.MapPath(), AppDomain.CurrentDomain.BaseDirecrory на крайній випадок

Тут погоджують, є певна незручність у використанні

>> А в цілому цікаве порівняння :)

Дякую

May 30, 2009 6:10 AM
Анонімні коментарі деактивовані. Увійдіть або Зареєструйтесь щоб мати доступ до ресурсів Спільноти.