public void SetSettings(MemberLevelSettingsValue value, int level)
        {
            var s = GetSettingsCopy(level);

            s.Basic = value;
            SetSettings(s, level);
        }
        public void SetLegacyFormat(ref MemberLevelSettingsValue level, MemberInfo member, RuntimeTypeModel model)
        {
            Type        type         = Helpers.GetMemberType(member);
            ValueFormat legacyFormat = ValueSerializerBuilder.GetDefaultLegacyFormat(type, model);

            switch (Helpers.GetTypeCode(type))
            {
            // these can't be registered and don't have AsReferenceDefault
            // explicitely set their asReference = false
            case ProtoTypeCode.String:
            case ProtoTypeCode.ByteArray:
            case ProtoTypeCode.Type:
            case ProtoTypeCode.Uri:
                level.Format = legacyFormat;
                break;

            default:
                if (!RuntimeTypeModel.CheckTypeCanBeAdded(model, type))
                {
                    // for primitive types - explicitly
                    level.Format = legacyFormat;
                }
                break;
            }
        }
예제 #3
0
        static RuntimeTypeModel CreateDefaultRefModel(bool aFirst, bool comp)
        {
            ProtoCompatibilitySettingsValue fullComp = ProtoCompatibilitySettingsValue.FullCompatibility;

            fullComp.SuppressValueEnhancedFormat = false;
            var model = TypeModel.Create(false, comp ? fullComp : ProtoCompatibilitySettingsValue.Incompatible);

            if (comp)
            {
                model.SkipForcedLateReference = true;
            }
            // otherwise will not be compatible
            model.SkipForcedAdvancedVersioning = true;
            if (aFirst)
            {
                model.Add(typeof(A_WithDefaultRef), true);
                model.Add(typeof(B_WithDefaultRef), true);
            }
            else
            {
                model.Add(typeof(B_WithDefaultRef), true);
                model.Add(typeof(A_WithDefaultRef), true);
            }

            ValueMember f = model[typeof(B_WithDefaultRef)][2];
            MemberLevelSettingsValue s = f.GetSettingsCopy(0);

            Assert.That(s.Format, Is.EqualTo(ValueFormat.NotSpecified));
            s.Format = ValueFormat.Compact;
            f.SetSettings(s);

            model.AutoCompile = false;

            return(model);
        }
 static void ResetCollectionSettings(ref MemberLevelSettingsValue level0)
 {
     level0.Collection.ItemType = null;
     level0.Collection.PackedWireTypeForRead = null;
     level0.Collection.Format               = CollectionFormat.NotSpecified;
     level0.Collection.ConcreteType         = null;
     level0.Collection.ArrayLengthReadLimit = null;
 }
예제 #5
0
 /// <summary>
 /// These settings are only applicable for collection types when they are serialized not as a member (root or LateReference)
 /// </summary>
 public void SetNestedSettingsWhenRoot(MemberLevelSettingsValue value, int level)
 {
     if (level == 0)
     {
         throw new ArgumentOutOfRangeException(nameof(level), "Zero level settings should be specified through DefaultX properties on MetaType");
     }
     ThrowIfFrozen();
     Helpers.MemoryBarrier();
     _rootNestedVs.SetSettings(value, level);
 }
예제 #6
0
        internal MetaType(RuntimeTypeModel model, Type type, MethodInfo factory)
        {
            this._factory = factory;
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            this._model = model;

            IProtoSerializer coreSerializer = model.TryGetBasicTypeSerializer(type);

            if (coreSerializer != null)
            {
                throw InbuiltType(type);
            }

            this.Type = type;

#if WINRT
            this._typeInfo = type.GetTypeInfo();
#endif

            MemberInfo[] members;

            _tupleCtor = ResolveTupleConstructor(Type, out members);
            if (_tupleCtor != null)
            {
                foreach (MemberInfo memberInfo in members)
                {
                    var level = new MemberLevelSettingsValue();
                    var vs    = new ValueSerializationSettings();
                    vs.SetSettings(new ValueSerializationSettings.LevelValue(level)
                    {
                        IsNotAssignable = true
                    }, 0);
                    vs.DefaultLevel = new ValueSerializationSettings.LevelValue(level.MakeDefaultNestedLevel());
                    var main = new MemberMainSettingsValue()
                    {
                        Name = memberInfo.Name
                    };
                    var vm = new ValueMember(main, vs, memberInfo, Type, model, canHaveDefaultValue: false, isAccessHandledOutside: true);
                    AddTupleField(vm);
                }
            }
        }
예제 #7
0
 public void SetSettings(MemberLevelSettingsValue value, int level = 0)
 {
     ThrowIfFrozen();
     Helpers.MemoryBarrier();
     _vsByClient.SetSettings(value, level);
 }
        ValueSerializationSettings.LevelValue CompleteLevel(ValueSerializationSettings vs, int levelNr, out object defaultValue)
        {
            var lv    = vs.GetSettingsCopy(levelNr);
            var level = lv.Basic; // do not use lv.Basic, it's overwritten at the end of this method

            var originalLevel = level;

            if (levelNr == 0)
            {
                //#if WINRT
                if (vs.DefaultValue != null && _model.MapType(vs.DefaultValue.GetType()) != level.EffectiveType)
                //#else
                //            if (defaultValue != null && !memberType.IsInstanceOfType(defaultValue))
                //#endif
                {
                    vs.DefaultValue = ParseDefaultValue(level.EffectiveType, vs.DefaultValue);
                }
                defaultValue = vs.DefaultValue;
            }
            else
            {
                defaultValue = null;
            }

            int      idx = _model.FindOrAddAuto(level.EffectiveType, false, true, false);
            MetaType effectiveMetaType = null;

            if (idx >= 0)
            {
                effectiveMetaType = _model[idx];
                var typeSettings = effectiveMetaType.GetFinalSettingsCopy();
                level = MemberLevelSettingsValue.Merge(typeSettings.Member, level);
            }

            MemberDefaultsMode defaultsMode = level.DefaultsMode.GetValueOrDefault();

            if (level.Format == ValueFormat.NotSpecified && defaultsMode == MemberDefaultsMode.Legacy)
            {
                level.Format = GetDefaultLegacyFormat(level.EffectiveType, _model);
            }

            if (level.Format == ValueFormat.LateReference)
            {
                if (vs.MaxSpecifiedNestedLevel > levelNr)
                {
                    throw new ProtoException("LateReference member levels can't have nested levels");
                }
                var defaultSettings = effectiveMetaType?.GetFinalSettingsCopy().Member ?? new MemberLevelSettingsValue().GetInitializedToValueOrDefault();
                if (level.ContentBinaryFormatHint.GetValueOrDefault() != defaultSettings.ContentBinaryFormatHint.GetValueOrDefault() ||
                    level.WriteAsDynamicType.GetValueOrDefault() != defaultSettings.WriteAsDynamicType.GetValueOrDefault() ||
                    level.Collection.Append.GetValueOrDefault() != defaultSettings.Collection.Append.GetValueOrDefault() ||
                    level.Collection.PackedWireTypeForRead != defaultSettings.Collection.PackedWireTypeForRead)
                {
                    throw new ProtoException("LateReference member levels can't override default member settings specified on MetaType");
                }
            }

            Type newCollectionConcreteType = null;
            Type newItemType = null;

            if (!effectiveMetaType?.GetFinalSettingsCopy().IgnoreListHandling ?? true)
            {
                MetaType.ResolveListTypes(_model, level.EffectiveType, ref newItemType, ref newCollectionConcreteType);
            }

            // tuples depend on collection
            if (defaultsMode == MemberDefaultsMode.LegacyTuple && level.Format == ValueFormat.NotSpecified && newItemType != null)
            {
                level.Format = ValueFormat.Compact;
            }

            EnsureCorrectFormatSpecified(_model, ref level.Format, level.EffectiveType, ref level.WriteAsDynamicType, true);

            #region Collections

            {
                if (effectiveMetaType?.GetFinalSettingsCopy().IgnoreListHandling ?? false)
                {
                    ResetCollectionSettings(ref level);
                }
                else
                {
                    // defaults for ItemType and others were already merged from type settings
                    if (level.Collection.ItemType != null)
                    {
                        if (level.Format == ValueFormat.LateReference)
                        {
                            Type defaultItemType = (effectiveMetaType?.GetFinalSettingsCopy().Member.Collection.ItemType ?? newItemType);
                            if (level.Collection.ItemType != defaultItemType)
                            {
                                throw new ProtoException("LateReference member settings level should have default collection item type (" + defaultItemType + ")");
                            }
                        }
                    }
                    else
                    {
                        level.Collection.ItemType = newItemType;
                    }

                    if (level.Collection.ItemType == null)
                    {
                        ResetCollectionSettings(ref level);
                    }
                    else
                    {
                        // should not override with default because: what if specified something like List<string> for IList?
                        if (level.Collection.ConcreteType != null)
                        {
                            if (!Helpers.IsAssignableFrom(level.EffectiveType, level.Collection.ConcreteType))
                            {
                                throw new ProtoException(
                                          "Specified CollectionConcreteType " + level.Collection.ConcreteType.Name + " is not assignable to " + level.EffectiveType);
                            }

                            if (level.Format == ValueFormat.LateReference)
                            {
                                Type defaultConcreteType = (effectiveMetaType?.GetFinalSettingsCopy().Member.Collection.ConcreteType ?? newCollectionConcreteType);
                                if (level.Collection.ConcreteType != defaultConcreteType)
                                {
                                    throw new ProtoException("LateReference member settings level should have default collection concrete type (" + defaultConcreteType + ")");
                                }
                            }
                        }
                        else
                        {
                            level.Collection.ConcreteType = newCollectionConcreteType;
                        }

                        if (!level.Collection.Append.GetValueOrDefault() && lv.IsNotAssignable)
                        {
                            if (level.Collection.Append == null)
                            {
                                level.Collection.Append = true;
                            }
                            else
                            {
                                throw new ProtoException("The property is not writable but AppendCollection was set to false");
                            }
                        }

                        if (!CanPack(level.Collection.ItemType, level.ContentBinaryFormatHint))
                        {
                            if (level.Collection.PackedWireTypeForRead != null && level.Collection.PackedWireTypeForRead != WireType.None)
                            {
                                throw new ProtoException("PackedWireTypeForRead " + level.Collection.PackedWireTypeForRead + " specified but type can't be packed");
                            }

                            level.Collection.PackedWireTypeForRead = WireType.None;
                        }

                        if (level.Collection.Format == CollectionFormat.NotSpecified)
                        {
                            level.Collection.Format = !_model.ProtoCompatibility.SuppressCollectionEnhancedFormat
                                                          ? CollectionFormat.Enhanced
                                                          : CollectionFormat.Protobuf;
                        }
                        else if (level.Collection.Format == CollectionFormat.Enhanced && _model.ProtoCompatibility.SuppressCollectionEnhancedFormat)
                        {
                            level.Collection.Format = CollectionFormat.Protobuf;
                        }
                    }
                }

                if (!level.EffectiveType.IsArray)
                {
                    if (level.Collection.ArrayLengthReadLimit != null)
                    {
                        throw new ProtoException("ArrayLengthReadLimit specified for non-array");
                    }
                }
                else if (level.Collection.ArrayLengthReadLimit == null)
                {
                    level.Collection.ArrayLengthReadLimit = TypeModel.DefaultArrayLengthReadLimit;
                }
                else if (level.Collection.ArrayLengthReadLimit <= 0)
                {
                    throw new ProtoException("ArrayLengthReadLimit should be greater than zero or not specified");
                }
            }

            #endregion

            lv.Basic = level.GetInitializedToValueOrDefault();

            vs.SetSettings(lv, levelNr);

            originalLevel.GetHashCode();

            return(lv);
        }
 static void ThrowIfHasMoreLevels(ValueSerializationSettings settings, int currentLevelNr, MemberLevelSettingsValue currentLevel, string description)
 {
     if (settings.MaxSpecifiedNestedLevel > currentLevelNr)
     {
         throw new ProtoException(
                   "Found unused specified nested level settings, maximum possible nested level is " + currentLevelNr + "-" + currentLevel.EffectiveType.Name + description);
     }
 }
 public bool CanBePackedCollection(MemberLevelSettingsValue level)
 {
     return(level.Collection.IsCollection &&
            CanPack(level.Collection.ItemType, level.ContentBinaryFormatHint) &&
            level.Collection.Format == CollectionFormat.Protobuf);
 }
        public MemberHandlerResult TryRead(AttributeMap attribute, MemberState s, MemberInfo member, RuntimeTypeModel model)
        {
            if (s.Input.IsEnumValueMember)
            {
                return(MemberHandlerResult.NotFound);
            }
            var main = s.MainValue;

            try
            {
                MemberLevelSettingsValue level = s.SerializationSettings.GetSettingsCopy(0).Basic;
                level.DefaultsMode = MemberDefaultsMode.Legacy;

                if (main.Tag <= 0)
                {
                    attribute.TryGetNotDefault("Tag", ref main.Tag);
                }
                if (string.IsNullOrEmpty(main.Name))
                {
                    attribute.TryGetNotEmpty("Name", ref main.Name);
                }
                if (!main.IsRequiredInSchema)
                {
                    attribute.TryGetNotDefault("IsRequired", ref main.IsRequiredInSchema);
                }

                var type = Helpers.GetMemberType(member);

                BinaryDataFormat dataFormat = 0;
                attribute.TryGetNotDefault("DataFormat", ref dataFormat);
                level.ContentBinaryFormatHint = dataFormat;

                bool isPacked = false;
                attribute.TryGetNotDefault("IsPacked", ref isPacked);
                level.Collection.Format = isPacked
                    ? CollectionFormat.Protobuf
                    : (model.ProtoCompatibility.SuppressCollectionEnhancedFormat
                        ? CollectionFormat.ProtobufNotPacked
                        : CollectionFormat.NotSpecified
                       );

                bool overwriteList = false;
                attribute.TryGetNotDefault("OverwriteList", ref overwriteList);
                level.Collection.Append = !overwriteList;

                if (!level.WriteAsDynamicType.GetValueOrDefault())
                {
                    attribute.TryGetNotDefault("DynamicType", ref level.WriteAsDynamicType);
                }
                bool dynamicType = level.WriteAsDynamicType.GetValueOrDefault();

                bool asRefHasValue  = false;
                bool notAsReference = false;
#if !FEAT_IKVM
                // IKVM can't access AsReferenceHasValue, but conveniently, AsReference will only be returned if set via ctor or property
                attribute.TryGetNotDefault("AsReferenceHasValue", ref asRefHasValue, publicOnly: false);
                if (asRefHasValue)
#endif
                {
                    bool value = false;
                    asRefHasValue = attribute.TryGetNotDefault("AsReference", ref value);
                    if (asRefHasValue) // if AsReference = true - use defaults
                    {
                        notAsReference = !value;
                    }
                }

                if (!asRefHasValue)
                {
                    if (level.Format == ValueFormat.NotSpecified)
                    {
                        SetLegacyFormat(ref level, member, model);
                    }
                }
                else
                {
                    level.Format = notAsReference ? ValueSerializerBuilder.GetDefaultLegacyFormat(type, model) : ValueFormat.Reference;
                }

                s.TagIsPinned = main.Tag > 0;

                var dl = s.SerializationSettings.DefaultLevel.GetValueOrDefault(new ValueSerializationSettings.LevelValue(level.MakeDefaultNestedLevelForLegacyMember()));

                if (isPacked)
                {
                    dl.Basic.Format = ValueFormat.Compact;
                }

                if (dynamicType)
                {
                    // apply dynamic type to items
                    Type itemType    = null;
                    Type defaultType = null;
                    MetaType.ResolveListTypes(model, Helpers.GetMemberType(s.Member), ref itemType, ref defaultType);
                    if (itemType != null)
                    {
                        dl.Basic.WriteAsDynamicType = true;
                        dl.Basic.Format             = ValueFormat.Reference;

                        if (level.Format == ValueFormat.Compact || level.Format == ValueFormat.MinimalEnhancement)
                        {
                            level.WriteAsDynamicType = false;
                        }
                    }
                }

                s.SerializationSettings.DefaultLevel = dl;
                s.SerializationSettings.SetSettings(level, 0);

                return(s.TagIsPinned ? MemberHandlerResult.Done : MemberHandlerResult.Partial); // note minAcceptFieldNumber only applies to non-proto
            }
            finally
            {
                s.MainValue = main;
            }
        }
예제 #12
0
        internal void WriteSchema(System.Text.StringBuilder builder, int indent, ref bool requiresBclImport)
        {
            Serializer.GetHashCode();
            if (_surrogate != null)
            {
                return;                     // nothing to write
            }
            ValueMember[] fieldsArr = new ValueMember[_fields.Count];
            _fields.CopyTo(fieldsArr, 0);
            Array.Sort(fieldsArr, ValueMember.Comparer.Default);

            if (IsList)
            {
                string itemTypeName = _model.GetSchemaTypeName(TypeModel.GetListItemType(_model, Type), BinaryDataFormat.Default, false, false, ref requiresBclImport);
                NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {");
                NewLine(builder, indent + 1).Append("repeated ").Append(itemTypeName).Append(" items = 1;");
                NewLine(builder, indent).Append('}');
            }
            else if (_settingsValueFinal.IsAutoTuple)
            { // key-value-pair etc
                MemberInfo[] mapping;
                if (ResolveTupleConstructor(Type, out mapping) != null)
                {
                    NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {");
                    for (int i = 0; i < mapping.Length; i++)
                    {
                        Type effectiveType;
                        if (mapping[i] is PropertyInfo)
                        {
                            effectiveType = ((PropertyInfo)mapping[i]).PropertyType;
                        }
                        else if (mapping[i] is FieldInfo)
                        {
                            effectiveType = ((FieldInfo)mapping[i]).FieldType;
                        }
                        else
                        {
                            throw new NotSupportedException("Unknown member type: " + mapping[i].GetType().Name);
                        }
                        NewLine(builder, indent + 1)
                        .Append("optional ")
                        .Append(_model.GetSchemaTypeName(effectiveType, BinaryDataFormat.Default, false, false, ref requiresBclImport).Replace('.', '_'))
                        .Append(' ').Append(mapping[i].Name).Append(" = ").Append(i + 1).Append(';');
                    }
                    NewLine(builder, indent).Append('}');
                }
            }
            else if (Helpers.IsEnum(Type))
            {
                NewLine(builder, indent).Append("enum ").Append(GetSchemaTypeName()).Append(" {");
                if (_settingsValueFinal.EnumPassthru.GetValueOrDefault())
                {
                    if (Type
#if WINRT
                        .GetTypeInfo()
#endif
                        .IsDefined(_model.MapType(typeof(FlagsAttribute)), false))
                    {
                        NewLine(builder, indent + 1).Append("// this is a composite/flags enumeration");
                    }
                    else
                    {
                        NewLine(builder, indent + 1).Append("// this enumeration will be passed as a raw value");
                    }
                    foreach (FieldInfo field in
#if WINRT
                             Type.GetRuntimeFields()
#else
                             Type.GetFields()
#endif
                             )
                    {
                        if (field.IsStatic && field.IsLiteral)
                        {
                            object enumVal;
#if WINRT || PORTABLE || CF || FX11
                            enumVal = field.GetValue(null);
#else
                            enumVal = field.GetRawConstantValue();
#endif
                            NewLine(builder, indent + 1).Append(field.Name).Append(" = ").Append(enumVal).Append(";");
                        }
                    }
                }
                else
                {
                    foreach (ValueMember member in fieldsArr)
                    {
                        NewLine(builder, indent + 1).Append(member.Name).Append(" = ").Append(member.FieldNumber).Append(';');
                    }
                }
                NewLine(builder, indent).Append('}');
            }
            else
            {
                NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {");
                foreach (ValueMember member in fieldsArr)
                {
                    member.Serializer.GetHashCode();
                    MemberLevelSettingsValue s = member.GetFinalSettingsCopy(0);
                    string ordinality          = s.Collection.IsCollection ? "repeated" : member.IsRequired ? "required" : "optional";
                    NewLine(builder, indent + 1).Append(ordinality).Append(' ');
                    if (s.ContentBinaryFormatHint.GetValueOrDefault() == BinaryDataFormat.Group)
                    {
                        builder.Append("group ");
                    }
                    string schemaTypeName = member.GetSchemaTypeName(true, ref requiresBclImport);
                    builder.Append(schemaTypeName).Append(" ")
                    .Append(member.Name).Append(" = ").Append(member.FieldNumber);

                    object defaultValue = member.GetFinalDefaultValue();
                    if (defaultValue != null && member.IsRequired == false)
                    {
                        if (defaultValue is string)
                        {
                            builder.Append(" [default = \"").Append(defaultValue).Append("\"]");
                        }
                        else if (defaultValue is bool)
                        { // need to be lower case (issue 304)
                            builder.Append((bool)defaultValue ? " [default = true]" : " [default = false]");
                        }
                        else
                        {
                            builder.Append(" [default = ").Append(defaultValue).Append(']');
                        }
                    }
                    if (s.Collection.IsCollection && s.Collection.Format == CollectionFormat.Protobuf &&
                        ListDecorator.CanPack(HelpersInternal.GetWireType(Helpers.GetTypeCode(member.MemberType), s.ContentBinaryFormatHint.GetValueOrDefault())))
                    {
                        builder.Append(" [packed=true]");
                    }
                    builder.Append(';');
                    if (schemaTypeName == "bcl.NetObjectProxy" && (s.Format == ValueFormat.Reference || s.Format == ValueFormat.LateReference) &&
                        !s.WriteAsDynamicType.GetValueOrDefault())    // we know what it is; tell the user
                    {
                        builder.Append(" // reference-tracked ").Append(member.GetSchemaTypeName(false, ref requiresBclImport));
                    }
                }
                if (_subTypes != null && _subTypes.Count != 0)
                {
                    NewLine(builder, indent + 1).Append("// the following represent sub-types; at most 1 should have a value");
                    SubType[] subTypeArr = new SubType[_subTypes.Count];
                    _subTypes.CopyTo(subTypeArr, 0);
                    Array.Sort(subTypeArr, SubType.Comparer.Default);
                    foreach (SubType subType in subTypeArr)
                    {
                        string subTypeName = subType.DerivedType.GetSchemaTypeName();
                        NewLine(builder, indent + 1).Append("optional ").Append(subTypeName)
                        .Append(" ").Append(subTypeName).Append(" = ").Append(subType.FieldNumber).Append(';');
                    }
                }
                NewLine(builder, indent).Append('}');
            }
        }
예제 #13
0
        internal void FinalizeSettingsValue()
        {
            if (_settingsValueFinalSet)
            {
                return;
            }

            int opaqueToken = 0;

            try
            {
                _model.TakeLock(ref opaqueToken);

                if (_settingsValueFinalSet)
                {
                    return;
                }

                _settingsValueFinal = _settingsValueByClient;

                ThrowIfInvalidSettings(_settingsValueFinal);
                FinalizingOwnSettings?.Invoke(this, new FinalizingOwnSettingsArgs(this));
                ThrowIfInvalidSettings(_settingsValueFinal);

                MemberLevelSettingsValue m = _settingsValueFinal.Member;

                if (_settingsValueFinal.EnumPassthru == null && Helpers.IsEnum(Type))
                {
#if WINRT
                    _settingsValueFinal.EnumPassthru = _typeInfo.IsDefined(typeof(FlagsAttribute), false);
#else
                    _settingsValueFinal.EnumPassthru = Type.IsDefined(_model.MapType(typeof(FlagsAttribute)), false);
#endif
                }

                if (_settingsValueFinal.IgnoreListHandling)
                {
                    m.Collection.ItemType = null;
                    m.Collection.Format   = CollectionFormat.NotSpecified;
                    m.Collection.PackedWireTypeForRead = null;
                }
                else if (m.Collection.ItemType == null)
                {
                    m.Collection.ItemType = Type.IsArray ? Type.GetElementType() : TypeModel.GetListItemType(_model, Type);
                }

                m.Collection.ConcreteType = _settingsValueFinal.ConstructType;

                if (_settingsValueFinal.PrefixLength == null && !IsSimpleValue)
                {
                    _settingsValueFinal.PrefixLength = true;
                }

                _settingsValueFinal.Member = m;

                Helpers.MemoryBarrier();
                _settingsValueFinalSet = true;
                IsFrozen = true;
            }
            finally
            {
                _model.ReleaseLock(opaqueToken);
            }
        }
 public ValueSerializationSettings(IEnumerable <MemberLevelSettingsValue?> levels, MemberLevelSettingsValue defaultLevel)
 {
     _levels      = new List <LevelValue?>(levels.Select(x => x != null ? new LevelValue(x.Value) : (LevelValue?)null) ?? new LevelValue?[0]);
     DefaultLevel = new LevelValue(defaultLevel);
 }
 public LevelValue(MemberLevelSettingsValue basic)
     : this()
 {
     Basic = basic;
 }