Я подозреваю в общем случае, это твердо; XML-схема допускает некоторые довольно причудливые конструкции типа. Я не уверен, как Вы сделали бы группы замены или расширения ограничений типов, например.
Однако должно быть возможно столкнуть что-то вполне быстро (особенно отображающийся от классов в Системе. Xml. Схема), который работает на 90% схем (т.е. последовательность и элементы выбора с несколькими простыми типами данных).
Я согласен с вами, что ?? обычно используется ограниченно - полезно предоставить запасное значение, если что-то имеет значение NULL, но бесполезно для предотвращения исключения нулевой ссылки в случаях, когда вы хотите продолжить детализацию свойств или методов иногда- пустая ссылка.
ИМХО, а чего нужно намного больше ?? - это оператор "разыменования нуля", который позволяет вам объединять длинные цепочки свойств и / или методов вместе, например ab (). cd (). e
, без необходимости проверять каждый промежуточный шаг на отсутствие значения NULL. В языке Groovy есть оператор безопасной навигации , и он очень удобен.
К счастью, похоже, что команда C # знает об этом пробеле в функциях. См. Предложение connect.microsoft.com для команды C # по добавлению оператора нулевого разыменования в язык C #.
Мы получаем довольно много запросов на функции, похожие на этот. Знак "?" версия, упомянутая в сообществе самое близкое нашему сердцу обсуждение - он позволяет вам проверять значение null на каждая "точка" и прекрасно сочетается с существующий ?? оператор:
a? .b? .c ?? d
Значение, если любой из a, ab или abc null используйте вместо этого d.
Мы рассматриваем это на будущее выпуск, но его не будет в C # 4.0.
Еще раз спасибо,
Mads Torgersen, C # Language PM
Если вам также нужна эта функция в C #, добавьте свои голоса к предложению на сайте подключения! : -)
Я использую один обходной путь, чтобы обойти отсутствие этой функции, - это метод расширения, подобный тому, который описан в этой записи блога , чтобы разрешить такой код:
string s = h.MetaData
.NullSafe(meta => meta.GetExtendedName())
.NullSafe(s => s.Trim().ToLower())
Этот код либо возвращает h.MetaData.GetExtendedName (). Trim (). ToLower ()
или возвращает значение null, если h, h.MetaData или h.MetaData.GetExtendedName () имеет значение null. Я также расширил это, чтобы проверять пустые или пустые строки, или пустые или пустые коллекции. Вот код, который я использую для определения этих методов расширения:
public static class NullSafeExtensions
{
/// <summary>
/// Tests for null objects without re-computing values or assigning temporary variables. Similar to
/// Groovy's "safe-dereference" operator .? which returns null if the object is null, and de-references
/// if the object is not null.
/// </summary>
/// <typeparam name="TResult">resulting type of the expression</typeparam>
/// <typeparam name="TCheck">type of object to check for null</typeparam>
/// <param name="check">value to check for null</param>
/// <param name="valueIfNotNull">delegate to compute if check is not null</param>
/// <returns>null if check is null, the delegate's results otherwise</returns>
public static TResult NullSafe<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNull)
where TResult : class
where TCheck : class
{
return check == null ? null : valueIfNotNull(check);
}
/// <summary>
/// Tests for null/empty strings without re-computing values or assigning temporary variables
/// </summary>
/// <typeparam name="TResult">resulting type of the expression</typeparam>
/// <param name="check">value to check for null</param>
/// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param>
/// <returns>null if check is null, the delegate's results otherwise</returns>
public static TResult CheckNullOrEmpty<TResult>(this string check, Func<string, TResult> valueIfNotNullOrEmpty)
where TResult : class
{
return string.IsNullOrEmpty(check) ? null : valueIfNotNullOrEmpty(check);
}
/// <summary>
/// Tests for null/empty collections without re-computing values or assigning temporary variables
/// </summary>
/// <typeparam name="TResult">resulting type of the expression</typeparam>
/// <typeparam name="TCheck">type of collection or array to check</typeparam>
/// <param name="check">value to check for null</param>
/// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param>
/// <returns>null if check is null, the delegate's results otherwise</returns>
public static TResult CheckNullOrEmpty<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNullOrEmpty)
where TCheck : ICollection
where TResult : class
{
return (check == null || check.Count == 0) ? null : valueIfNotNullOrEmpty(check);
}
}
?? [ Оператор 1140151] похож на метод coalesce в SQL, он возвращает вам первое ненулевое значение.
var result = value1 ?? value2 ?? value3 ?? value4 ?? defaultValue;
Я обычно использую его для строк или типов, допускающих значение NULL.
string s = someString ?? "Default message";
проще, чем
string s;
if(someString == null)
s = "Default Message";
else
s = someString;
или
string s = someString != null ? someString : "Default Message";
Я часто использую его для ленивых экземпляров объектов в свойствах, например
public MyObject MyProperty
{
get
{
return this.myField ?? (this.myField = new MyObject());
}
}
Это использует тот факт, что в C # присваивание является выражением, поэтому вы можете назначать и использовать результат выражения (присвоенное значение) все в одном заявлении. Я все еще чувствую себя немного грязным по поводу этого шаблона кода, но он короче, чем альтернатива (ниже), так что он почти выигрывает.
public MyObject MyProperty
{
get
{
if (this.myField == null)
{
this.myField = new MyObject();
}
return this.myField;
}
}
?? фактически является оператором проверки на null.
Причина, по которой ваш код попадает в затруднительное положение, заключается в том, что если «someObject имеет значение null, то .someMember является свойством для нулевого объекта. Сначала вам нужно будет проверить someObject на значение null.
РЕДАКТИРОВАТЬ:
Я должен добавить, что да, я нахожу ?? очень полезным, особенно при обработке ввода в базу данных, особенно из LINQ, но также и в других случаях. Я часто его использую.
Как и в случае с FYI, тернарный оператор генерирует последовательность IL, отличную от нулевого оператора объединения. Первый выглядит примерно так:
// string s = null;
// string y = s != null ? s : "Default";
ldloc.0
brtrue.s notnull1
ldstr "Default"
br.s isnull1
notnull1: ldloc.0
isnull1: stloc.1
А второй выглядит примерно так:
// y = s ?? "Default";
ldloc.0
dup
brtrue.s notnull2
pop
ldstr "Default"
notnull2: stloc.1
Исходя из этого, я бы сказал, что нулевой оператор объединения оптимизирован для своей цели, а не просто синтаксический сахар.
Я использовал его с материалом App.Config
string somethingsweet = ConfigurationManager.AppSettings["somesetting"] ?? "sugar";
Часто кажется хорошей идеей заменить подробный синтаксис более компактной формой. Но обычно это заканчивается просто запутыванием кода, ничего не получая. Современные стандарты рекомендуют более длинные и описательные имена переменных и использование более подробных стилей макета, чтобы сделать код более читаемым и понятным. более удобен в обслуживании.
Если я собираюсь научить свой мозг быстро разбирать ??, мне нужно найти ситуацию, в которой он показывает явное преимущество - то, что нельзя сделать другим способом, или где-нибудь, что позволяет значительный объем набора.
И это где ?? падает для меня. Это так редко бывает полезно, и?: И if / else - такие быстрые и удобочитаемые альтернативы, что действительно не имеет смысла использовать другой синтаксис, который не дает ничего нового.
a = b ?? с ?? г ?? е; звучит здорово. Но мне никогда не приходилось это делать!
Что меня раздражает, так это то, что я хочу использовать ??, но каждый раз, когда я думаю: «Ох, может, я могу использовать ?? здесь», я понимаю, что не Я хочу использовать сам объект, но его член.
name = (user == null)? "лань": user.Surname;
И, к сожалению, ?? не
Я использую его при работе с методами, которые могут возвращать значение null при нормальной работе.
, например, допустим, что у меня есть класс контейнера, который имеет метод Get, который возвращает значение null, если контейнер не содержит ключа ( или, возможно, null - допустимая ассоциация). Тогда я мог бы сделать что-то вроде этого:
string GetStringRep(object key) {
object o = container.Get(key) ?? "null";
return o.ToString();
}
очевидно, эти две последовательности эквивалентны:
foo = bar != null ? bar : baz;
foo = bar ?? baz;
Вторая просто более лаконична.
В вашем случае вы можете создать DefaultObject как статическое свойство и использовать, как показано ниже ...
var x = (someObject as someType ?? someType.DefaultObject).someMember;
Где ваш DefaultObject будет возвращать статический объект только для чтения.
Например, EventArgs.Empty, String.Empty и т. Д. ...
У меня была точно такая же проблема, как и у вас, но при использовании LinqToXML тега может не быть в документе, поэтому использование ??
нецелесообразно для использования свойства этого тега.
Поскольку в C # нет такой вещи, как глобальные переменные, все находится в классе, поэтому я, как и вы, обнаружил, что ?? в основном бесполезен.
Даже простой метод получения свойств, например:
MyObject MyObj() { get { return _myObj ?? new MyObj(); } }
Вероятно, лучше обслуживается инициализатором ...
Я полагаю, что, как и в SQL, он был бы полезен в запросах Linq, но я не могу действительно получить один в данный момент.
Я использую оператор объединения с нулем часто при синтаксическом анализе строк в другие типы данных. У меня есть набор методов расширения, которые обертывают такие вещи, как Int32.TryParse, и возвращают обнуляемый int вместо того, чтобы предоставлять выходной параметр остальной части моего кода. Затем я могу проанализировать строку и указать значение по умолчанию, если синтаксический анализ завершился неудачно, в одной строке кода.
// ToNullableInt(), is an extension method on string that returns null
// if the input is null and returns null if Int32.TryParse fails.
int startPage = Request.QueryString["start"].ToNullableInt() ?? 0;
The most useful is when dealing with nullable types.
bool? whatabool;
//...
bool realBool = whatabool ?? false;
without ?? you would need to write the following, which is much more confusing.
bool realbool = false;
if (whatabool.HasValue)
realbool = whatabool.Value;
I find this operator very useful for nullable types, but other than that I don't find myself using it very much. Definitely a cool shortcut.