C# blic覆盖布尔等于(对象对象obj)=>(对象obj作为MaybeX?)等于(此)??虚假的; ///测试值是否相等,如果其中一个值不存在,则返回false。 [纯] 公共布尔等于(可能是其他)=> _价值!=无效的其他。_值!=空值&(_值==其他._

C# blic覆盖布尔等于(对象对象obj)=>(对象obj作为MaybeX?)等于(此)??虚假的; ///测试值是否相等,如果其中一个值不存在,则返回false。 [纯] 公共布尔等于(可能是其他)=> _价值!=无效的其他。_值!=空值&(_值==其他._,c#,extension-methods,C#,Extension Methods,blic覆盖布尔等于(对象对象obj)=>(对象obj作为MaybeX?)等于(此)??虚假的; ///测试值是否相等,如果其中一个值不存在,则返回false。 [纯] 公共布尔等于(可能是其他)=> _价值!=无效的其他。_值!=空值&(_值==其他._值| | _值.等于(其他._值)) :其他。_值==null; ///检索属性返回的对象的哈希代码。 [纯] 公共覆盖int GetHashCode()=>(\u值==null)?0:_value.GetHashCode(); ///测试值是

blic覆盖布尔等于(对象对象obj)=>(对象obj作为MaybeX?)等于(此)??虚假的; ///测试值是否相等,如果其中一个值不存在,则返回false。 [纯] 公共布尔等于(可能是其他)=> _价值!=无效的其他。_值!=空值&(_值==其他._值| | _值.等于(其他._值)) :其他。_值==null; ///检索属性返回的对象的哈希代码。 [纯] 公共覆盖int GetHashCode()=>(\u值==null)?0:_value.GetHashCode(); ///测试值是否相等,如果其中一个值不存在,则返回false。 [纯] 公共静态布尔运算符==(MaybeX lhs,MaybeX rhs)=>lhs.Equals(rhs); ///测试值不相等,如果其中一个值不存在,则返回false。。 [纯] 公共静态布尔运算符!=(MaybeX lhs,MaybeX rhs)=>!lhs等于(rhs); ///测试值是否相等,如果其中一个值不存在,则返回。 [纯] 公共场所?AreNonNullEqual(MaybeX rhs)=> this.HasValue&&rhs.HasValue?此值等于(rhs值) :null为bool?; ///测试值是否相等,如果其中一个值不存在,则返回。 [纯] 公共场所?ARENONNULLINQUALE(MaybeX rhs)=> this.HasValue&&rhs.HasValue!此值等于(rhs值) :null为bool?; #端区 /// [纯] 公共重写字符串ToString(){ 确保(Result()!=null); 返回SelectMany(v=>v.ToString())|“”; } } [纯] 公共静态类MaybeX{ ///将引用类型T放大为MaybeX{T}。 ///单子单位函数。 公共静态MaybeX AsMaybeX(this T@this),其中T:class=>@this; ///将引用类型T放大为MaybeX{T}。 ///单子单位函数。 公共静态MaybeX-ToMaybeX(this T@this),其中T:struct=>@this; ///返回基础类型{TValue}的类型。 [SuppressMessage(“Microsoft.Usage”,“CA1801:ReviewUnusedParameters”,MessageId=“this”)] 公共静态类型GetUnderlyingType(this MaybeX@this),其中T:class{ 确保(Result()!=null); 返回类型(T); } 公共静态MaybeX Cast(this MaybeX@this),其中T:class=> 从@this中的o选择(T)o; } ///用于增强代码契约和与代码分析集成的扩展方法。 [纯] 公共静态类扩展{ ///如果值为null,则引发ContractException{name}。 ///要测试的值。 ///正在测试的参数的名称,用于引发的异常。 [SuppressMessage(“Microsoft.Usage”,“CA1801:ReviewUnusedParameters”,MessageId=“value”)] [SuppressMessage(“Microsoft.Usage”,“CA1801:ReviewUnusedParameters”,MessageId=“name”)] [ContractAbreviator]//需要组装模式=标准合同需要 [调试步骤至] #如果调试 [MethodImpl(MethodImplOptions.noInLine)] #否则 [MethodImpl(MethodImplOptions.AggressiveInline)] #恩迪夫 公共静态void ContractedNotNull([ValidatedNotNull]此T值,字符串名称){ 需要(值!=null,名称); } ///对象的装饰器,假定其对象不变量。 [SuppressMessage(“Microsoft.Usage”,“CA1801:ReviewUnusedParameters”,MessageId=“t”)] 公共静态空假设不变量(此T{} ///约定强制为NotNull的传入参数的装饰器。 [AttributeUsage(AttributeTargets.Parameter,AllowMultiple=false)] 公共密封类ValidatedNotNullAttribute:属性{} } }
Elvis操作员,我喜欢。这不是Elvis操作员。请看:我称之为“独眼Elvis运算符”
?:
是C#::
?。
是空条件运算符:抱歉,但答案应该给出一个扩展方法解决方案。它确实使用扩展,你的意思是不能向类添加属性?就像真正的Elvis一样-它应该扩展任何对象类型。Pieter,“下一步”后如何使用它?@N.D.B:我的gitHub上完整解决方案的示例:。今晚下班后我会在这里发一些东西。
//C# 6.0 way
var g1 = parent?.child?.child?.child; 
if (g1 != null) // TODO

//C# 5.0 way
var g1 =   parent.elvisExtension().child.elvisExtension().child.elvisExtension().child; 
if (g1 != null) // TODO
public static class Helper
{
    public static TReturnType Elvis<TOnType, TReturnType>(this TOnType onObj, Func<TOnType, TReturnType> selector)
        where TReturnType : class
    {
        if (onObj == null)
            return null;
        return selector(onObj);
    }
}
var person = new Person { Parent = new Person { Parent = new Person() } };
var result = person.Elvis(p => p.Parent).Elvis(p => p.Parent);
person = new Person();
result = person.Elvis(p => p.Parent).Elvis(p => p.Parent);
public static TReturnType? Elviss<TOnType, TReturnType>(this TOnType onObj, Func<TOnType, TReturnType> selector)
    where TReturnType : struct
{
    if (onObj == null)
        return default(Nullable<TReturnType>);
    return selector(onObj);
}
var result = person.Elvis(p => p.Parent).Elviss(p => p.Id);
        var getter = parent != null ? 
                        parent.Child != null ? 
                            parent.Child.Child != null ? 
                                parent.Child.Child 
                                    : null : null : null;
        //or
        var getter2 = parent == null ? null : 
                        parent.Child == null ? null : 
                            parent.Child.Child == null ? null : 
                                parent.Child.Child;
public class ParentClass
{
    public ParentClass(bool flag = false)
    {
        this.NullFlag = flag;
    }

    public ParentClass Child { get; set; }

    public readonly bool NullFlag { get; set; }
}

public static class ParentClassExtenstion
{
    public static ParentClass GetChild(this ParentClass parent)
    {

        if (parent.Child == null)
        {
            parent.Child = new ParentClass(true);
        }
        return parent.Child;
    }
}
        var getter3 = parent.GetChild().GetChild().GetChild();

        if (!getter3.NullFlag) 
        {
            //safe;
        }
using System;

namespace ConsoleApplication1 {
    public class Program { 
        public static void Main() {
            var s1 = "String1";
            var s2 = "String2";
            var s3 = (string)null;

            Console.WriteLine((from u in s1
                               from v in s2
                               select u.Replace("1", "45") + " " 
                                    + v.Replace("2", "33")) ?? "Nothing");

            Console.WriteLine((from u in s1
                               from v in s3
                               select u.Replace("1", "45") + " " 
                                    + v.Replace("2", "33")) ?? "Nothing");
            Console.ReadLine();
        }
    }

    public static class Extensions {
        public static TResult Select<TValue, TResult>(this
            TValue @this,
            Func<TValue, TResult> projector
        ) where TValue : class where TResult : class {
            return @this==null ? null : projector(@this);
        }

        public static TResult SelectMany<TValue, T, TResult>(this
            TValue @this,
            Func<TValue, T> selector,
            Func<TValue, T, TResult> resultSelector
        ) where TValue : class where TResult : class where T : class {
            return @this==null ? null : selector(@this).Select(e => resultSelector(@this, e)); ;
        }
    }
}
String45 String33
Nothing
using System;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;

namespace PGSolutions.Utilities.Monads {
    using static Contract;

    /// <summary>An immutable value-type MaybeX{T} monad.</summary>
    /// <typeparam name="TValue">The base type, which can be either a class or struct type,
    /// and will have the Equality definition track the default for the base-type:
    /// Value-equality for structs and string, reference equality for other classes.
    /// </typeparam>
    /// <remarks
    /// >Being a value-type reduces memory pressure on <see cref="System.GC"/>.
    /// 
    /// Equality tracks the base type (struct or class), with the further proviseo
    /// that two instances can only be equal when <see cref="HasValue"/> is true
    /// for both instances.
    /// </remarks>
    public struct MaybeX<T> : IEquatable<MaybeX<T>> where T:class {
        /// <summary>The Invalid Data value.</summary>
        [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
        public static MaybeX<T> Nothing { get { return default(MaybeX<T>); } }

        ///<summary>Create a new MaybeX{T}.</summary>
        private MaybeX(T value) : this() {
            _value    = value;
        }

        /// <summary>LINQ-compatible implementation of the monadic map operator.</summary>
        ///<remarks>
        /// Used to implement the LINQ <i>let</i> clause and queries with a single FROM clause.
        /// 
        /// Always available from Bind():
        ///         return @this.Bind(v => projector(v).ToMaybe());
        ///</remarks>
        public MaybeX<TResult>  Select<TResult>(
            Func<T, TResult> projector
        ) where TResult : class {
            projector.ContractedNotNull(nameof(projector));

            return (_value == null) ? default(MaybeX<TResult>) : projector(_value);
        }

        ///<summary>The monadic Bind operation of type T to type MaybeX{TResult}.</summary>
        /// <remarks>
        /// Convenience method - not used by LINQ
        /// </remarks>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        [Pure]
        public  MaybeX<TResult> SelectMany<TResult>(
            Func<T, MaybeX<TResult>> selector
        ) where TResult:class {
            selector.ContractedNotNull(nameof(selector));

            return (_value == null) ? default(MaybeX<TResult>) : selector(_value);
        }

        /// <summary>LINQ-compatible implementation of the monadic join operator.</summary>
        /// <remarks>
        /// Used for LINQ queries with multiple <i>from</i> clauses or with more complex structure.
        /// </remarks>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public MaybeX<TResult> SelectMany<TIntermediate, TResult>(
            Func<T, MaybeX<TIntermediate>> selector,
            Func<T,TIntermediate,TResult> projector
        ) where TIntermediate:class where TResult:class {
            selector.ContractedNotNull(nameof(selector));
            projector.ContractedNotNull(nameof(projector));

            var @this = this;
            return (_value == null) ? default(MaybeX<TResult>)
                                    : selector(_value).Select(e => projector(@this._value, e));
        }

        ///<summary>Returns whether this MaybeX{T} has a value.</summary>
        public bool HasValue {
            get {
                Ensures((_value != null) == HasValue);
                return _value != null;
            }
        }

        ///<summary>Extract value of the MaybeX{T}, substituting <paramref name="defaultValue"/> as needed.</summary>
        [Pure]
        public T BitwiseOr(T defaultValue) {
            defaultValue.ContractedNotNull(nameof(defaultValue));
            Ensures(Result<T>() != null);

            return _value ?? defaultValue;
        }
        ///<summary>Extract value of the MaybeX{T}, substituting <paramref name="defaultValue"/> as needed.</summary>
        [Pure]
        public static T operator | (MaybeX<T> value, T defaultValue) {
            defaultValue.ContractedNotNull(nameof(defaultValue));
            Ensures(Result<T>() != null);

            return value.BitwiseOr(defaultValue);
        }

        ///<summary>The invariants enforced by this struct type.</summary>
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        [ContractInvariantMethod]
        [Pure]
        private void ObjectInvariant() {
            Invariant(HasValue == (_value != null));
        }

        ///<summary>Wraps a T as a MaybeX{T}.</summary>
        [Pure]
        public static implicit operator MaybeX<T>(T value) => new MaybeX<T>(value);

        readonly T _value;

        #region Value Equality with IEquatable<T>.
        /// <inheritdoc/>
        [Pure]
        public override bool Equals(object obj) => (obj as MaybeX<T>?)?.Equals(this) ?? false;

        /// <summary>Tests value-equality, returning <b>false</b> if either value doesn't exist.</summary>
        [Pure]
        public bool Equals(MaybeX<T> other)  =>
            _value != null ? other._value != null && (_value == other._value || _value.Equals(other._value))
                           : other._value == null;

        ///<summary>Retrieves the hash code of the object returned by the <see cref="_value"/> property.</summary>
        [Pure]
        public override int GetHashCode() => (_value == null) ? 0 : _value.GetHashCode();

        /// <summary>Tests value-equality, returning false if either value doesn't exist.</summary>
        [Pure]
        public static bool operator == (MaybeX<T> lhs, MaybeX<T> rhs) => lhs.Equals(rhs);

        /// <summary>Tests value-inequality, returning false if either value doesn't exist..</summary>
        [Pure]
        public static bool operator != (MaybeX<T> lhs, MaybeX<T> rhs) => ! lhs.Equals(rhs);

        ///<summary>Tests value-equality, returning <see cref="null"/> if either value doesn't exist.</summary>
        [Pure]
        public bool? AreNonNullEqual(MaybeX<T> rhs) =>
            this.HasValue && rhs.HasValue ? this._value.Equals(rhs._value)
                                          : null as bool?;

        ///<summary>Tests value-equality, returning <see cref="null"/> if either value doesn't exist.</summary>
        [Pure]
        public bool? AreNonNullUnequal(MaybeX<T> rhs) =>
            this.HasValue && rhs.HasValue ? ! this._value.Equals(rhs._value)
                                          : null as bool?;
        #endregion

        /// <inheritdoc/>
        [Pure]
        public override string ToString() {
            Ensures(Result<string>() != null);
            return SelectMany<string>(v => v.ToString()) | "";
        }
    }

    [Pure]
    public static class MaybeX {
        ///<summary>Amplifies a reference-type T to a MaybeX{T}.</summary>
        ///<remarks>The monad <i>unit</i> function.</remarks>
        public static MaybeX<T> AsMaybeX<T>(this T @this) where T:class => @this;

        ///<summary>Amplifies a reference-type T to a MaybeX{T}.</summary>
        ///<remarks>The monad <i>unit</i> function.</remarks>
        public static MaybeX<object> ToMaybeX<T>(this T @this) where T : struct => @this;

        ///<summary>Returns the type of the underlying type {TValue}.</summary>
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "this")]
        public static Type GetUnderlyingType<T>(this MaybeX<T> @this) where T:class {
            Ensures(Result<System.Type>() != null);
            return typeof(T);
        }

        public static MaybeX<T> Cast<T>(this MaybeX<object> @this) where T:class =>
            from o in @this select (T)o;
    }

    /// <summary>Extension methods to enhance Code Contracts and integration with Code Analysis.</summary>
    [Pure]
    public static class ContractExtensions {

        /// <summary>Throws <c>ContractException{name}</c> if <c>value</c> is null.</summary>
        /// <param name="value">Value to be tested.</param>
        /// <param name="name">Name of the parameter being tested, for use in the exception thrown.</param>
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value")]
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "name")]
        [ContractAbbreviator] // Requires Assemble Mode = Standard Contract Requires
        [DebuggerStepThrough]
#if DEBUG
        [MethodImpl(MethodImplOptions.NoInlining)]
#else
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void ContractedNotNull<T>([ValidatedNotNull]this T value, string name) {
            Requires(value != null, name);
        }

        /// <summary>Decorator for an object which is to have it's object invariants assumed.</summary>
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "t")]
        public static void AssumeInvariant<T>(this T t) { }


        /// <summary>Decorator for an incoming parameter that is contractually enforced as NotNull.</summary>
        [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
        public sealed class ValidatedNotNullAttribute : Attribute {}
    }
}