#c# #linq #driveinfo
#c# #linq #driveinfo
Вопрос:
Я знаю, что есть много способов выполнить то, что я пытаюсь сделать здесь, но я хотел попробовать это с LINQ, и я вижу некоторые странные (для меня) результаты. Надеюсь, у кого-нибудь здесь есть какая-то мудрость, чтобы предложить мне.
Цель состоит в том, чтобы найти диск на локальной машине, на котором мы выполняем, с максимально доступным свободным пространством, отформатированным в файловой системе NTFS, исключая том %SystemDrive%, если это возможно. Еще одно предостережение заключается в том, что диски, которым присвоена буква тома, но которые еще не были отформатированы, должны быть исключены из пула кандидатов. Это крайний случай, но один клиент уже сталкивался с ним.
Итак, я пытаюсь:
string systemDrive = Environment.GetEnvironmentVariable("SystemDrive") "\";
List<DriveInfo> localDrives = DriveInfo.GetDrives().ToList();
var bestAPIDataDrives = from localDrive in localDrives
orderby localDrive.AvailableFreeSpace descending
where localDrive.DriveType == DriveType.Fixed amp;amp;
localDrive.DriveFormat == "NTFS" amp;amp;
localDrive.RootDirectory.FullName != systemDrive amp;amp;
localDrive.IsReady
select localDrive.RootDirectory.FullName;
string path = String.Empty;
if (bestAPIDataDrives.Count() == 0)
{
// there is only a system drive available, use it anyway.
path = systemDrive;
}
else
{
path = bestAPIDataDrives.ElementAt(0).ToString();
}
Когда я доберусь до bestAPIDataDrives.По ссылке Count() я получаю исключение IOException со свойством Message, для которого установлено значение «Устройство не готово».
Я не понимаю, почему это происходит, потому что у меня localDrive.Готов ли тест в запросе LINQ, или, по крайней мере, я думаю, что готов.
Комментарии:
1. Марк ответил на реальный вопрос, поэтому два комментария к обзору кода: Этот код фактически выполняет запрос дважды, один раз для подсчета и еще раз для поиска первого элемента. Вам также не обязательно вводить строку. Все, что после построения запроса, может быть заменено на
string path = bestAPIDataDrives.FirstOrDefault() ?? systemDrive
. Вам также не нужно создавать список из результатовDriveInfo.GetDrives()
, и вы можете сказатьIEnumerable<DriveInfo> localDrives = DriveInfo.GetDrives()
.2. @Chris — хорошее место; Я определенно согласен — следует использовать
FirstOrDefault()
здесь (и ничего больше; это охватывает обаCount()
иElementAt()
, гораздо эффективнее)3. Еще раз хороший совет для всех. Большое спасибо. Обновит решение с помощью этих элементов проверки кода.
Ответ №1:
это LINQ-to-Objects, поэтому он будет выполнять операции в представленном порядке; в частности, он попытается выполнить сортировку перед фильтрацией, и почти все фильтры выполняются перед тестированием ключа IsReady
. Я бы просто изменил их порядок:
var bestAPIDataDrives = from localDrive in localDrives
where localDrive.IsReady amp;amp;
localDrive.DriveType == DriveType.Fixed amp;amp;
localDrive.DriveFormat == "NTFS" amp;amp;
localDrive.RootDirectory.FullName != systemDrive
orderby localDrive.AvailableFreeSpace descending
select localDrive.RootDirectory.FullName;
Выполнение сортировки после фильтров в любом случае является хорошей идеей, поскольку вы снижаете стоимость сортировки (которая всегда является суперлинейной)
Как отмечает Крис, затем вы просто хотите закончить с:
string path = bestAPIDataDrives.FirstOrDefault() ?? systemDrive;