Честно говоря, мне нравится первый способ OP начать его с помощью значения NULL
, а затем проверить его с помощью is.null
(в первую очередь потому, что это очень просто и легко понять). Возможно, это зависит от того, как люди привыкли к кодированию, но Хэдли, похоже, поддерживает и путь is.null
:
Из книги Хэдли «Advanced-R» Глава 6, Функции, стр.84 (для здесь ):
Вы можете определить, был ли аргумент предоставлен или нет с функцией missing ().
i <- function(a, b) { c(missing(a), missing(b)) } i() #> [1] TRUE TRUE i(a = 1) #> [1] FALSE TRUE i(b = 2) #> [1] TRUE FALSE i(1, 2) #> [1] FALSE FALSE
Иногда вы хотите добавить нетривиальное значение по умолчанию, которое может занять несколько строк кода. Вместо того, чтобы вставлять этот код в определение функции, вы можете использовать missing () для условного вычисления, если это необходимо. Однако это затрудняет понимание того, какие аргументы необходимы и которые являются необязательными, без тщательного изучения документации. Вместо этого я обычно устанавливаю значение по умолчанию NULL и использую is.null (), чтобы проверить, был ли предоставлен аргумент.
|DataDirectory|
не является файлом как таковым. Цитата из этой довольно старой статьи MSDN (подробнее читайте в полной статье):
По умолчанию переменная | DataDirectory | будет расширена как следуйте:
- Для приложений, размещенных в каталоге на пользовательском компьютере, это будет папка приложения (.exe).
- Для приложений, работающих под ClickOnce, это будет специальная папка данных, созданная ClickOnce.
- Для веб-приложений это будет папка App_Data.
. для | DataDirectory | просто происходит из свойства в домене приложения. Можно изменить это значение и переопределить поведение по умолчанию, выполнив следующее:
AppDomain.CurrentDomain.SetData("DataDirectory", newpath)
Еще одна цитата относительно несоответствий вашей схемы:
Одна из вещей знать при работе с локальными файлами базы данных, что они обрабатываются как любые другие файлы содержимого. Для настольных проектов это означает, что по умолчанию файл базы данных будет копироваться в выходную папку (он же bin) при каждой сборке проекта. После F5 вот как это будет выглядеть на диске
MyProject\Data.mdf MyProject\MyApp.vb MyProject\Bin\Debug\Data.mdf MyProject\Bin\Debug\MyApp.exe
Во время разработки MyProject \ Data.mdf используется инструментами данных. Во время выполнения приложение будет использовать базу данных в выходной папке. В результате копирования у многих создалось впечатление, что приложение не сохранило данные в файл базы данных. На самом деле это просто потому, что задействованы две копии файла данных. То же самое касается просмотра схемы / данных через проводник баз данных. Инструменты используют копию в проекте, а не ту, которая находится в папке bin.
На форуме MSDN есть похожий, но упрощенный вопрос об этом, который говорит:
По умолчанию | DataDirectory | указывает на папку вашего приложения (как вы выяснили в исходном вопросе: на App_Data).
Так как это просто путь замещения к вашей базе данных, вы можете сами определить путь с помощью AppDomain.SetData .
Каталог данных | Алгоритм находится в сборке System.Data.dll, во внутреннем классе System.Data.Common.DbConnectionOptions. Вот как показано ILSpy (обратите внимание на источник, который теперь доступен в репозитории справочных источников: https://github.com/Microsoft/referencesource/blob/e458f8df6ded689323d4bd1a2a725ad32668aaec/System.Data.Entity/ System / Data / EntityClient / DbConnectionOptions.cs ):
internal static string ExpandDataDirectory(string keyword,
string value,
ref string datadir)
{
string text = null;
if (value != null &&
value.StartsWith("|datadirectory|", StringComparison.OrdinalIgnoreCase))
{
string text2 = datadir;
if (text2 == null)
{
// 1st step!
object data = AppDomain.CurrentDomain.GetData("DataDirectory");
text2 = (data as string);
if (data != null && text2 == null)
throw ADP.InvalidDataDirectory();
if (ADP.IsEmpty(text2))
{
// 2nd step!
text2 = AppDomain.CurrentDomain.BaseDirectory;
}
if (text2 == null)
{
text2 = "";
}
datadir = text2;
}
// 3rd step, checks and normalize
int length = "|datadirectory|".Length;
bool flag = 0 < text2.Length && text2[text2.Length - 1] == '\\';
bool flag2 = length < value.Length && value[length] == '\\';
if (!flag && !flag2)
{
text = text2 + '\\' + value.Substring(length);
}
else
{
if (flag && flag2)
{
text = text2 + value.Substring(length + 1);
}
else
{
text = text2 + value.Substring(length);
}
}
if (!ADP.GetFullPath(text).StartsWith(text2, StringComparison.Ordinal))
throw ADP.InvalidConnectionOptionValue(keyword);
}
return text;
}
Таким образом, сначала он просматривает текущие данные AppDomain (по умолчанию нет данных «DataDirectory», определенных, как мне кажется), а затем получает в текущий базовый каталог AppDomain. Остальное в основном проверяет корни путей и нормализацию путей.