static bool ShouldSkipProperty(MemberConfig m) { var p = (PropertyInfo)m.Member; // There's no way we can serialize a prop that we can't write. // If it would have a { private set; } that would work, but it doesn't. var accessors = p.GetAccessors(true); if (accessors.Length <= 1) { // It's a "computed" property, which has no concept of writing. m.ExcludeWithReason("Computed Property (has no 'set' function, not even a private one)"); return(true); } return(false); }
// Use attributes on the members to further specialize the settings. // We're only setting some *defaults* here, that can later be overriden some more. internal static void ApplyMemberAttributes(MemberConfig memberConfig) { var type = memberConfig.TypeConfig.Type; var memberInfo = memberConfig.Member; // Skip compiler generated if (memberConfig.IsCompilerGenerated) { if (memberConfig.TypeConfig.Config.Advanced.SkipCompilerGeneratedFields) { memberConfig.ExcludeWithReason("Compiler generated field"); return; } } if (memberInfo is FieldInfo f) { var readOnlyConfig = f.GetCustomAttribute <ReadonlyConfigAttribute>(true); if (readOnlyConfig != null) { memberConfig.ReadonlyFieldHandling = readOnlyConfig.ReadonlyFieldHandling; } } else if (memberInfo is PropertyInfo p) { // prop: skip computed if (ShouldSkipProperty(memberConfig)) { return; } } else { throw new InvalidOperationException(memberInfo.Name + " must be a field or a property"); } // [Include] / [Exclude] / [NonSerialized] var hasExclude = memberInfo.GetCustomAttribute <ExcludeAttribute>(true) != null; var hasInclude = memberInfo.GetCustomAttribute <IncludeAttribute>(true) != null; var hasNonSerialized = memberInfo.GetCustomAttribute <NonSerializedAttribute>(true) != null; if (hasInclude && (hasExclude || hasNonSerialized)) { throw new Exception($"Member '{memberInfo.Name}' on type '{type.Name}' has both [Include] and [Exclude] (or [NonSerialized]) !"); } if (hasExclude) { memberConfig.ExcludeWithReason("[Exclude] attribute"); } if (hasNonSerialized) { memberConfig.HasNonSerialized = true; } if (hasInclude) { memberConfig.SetIncludeWithReason(SerializationOverride.ForceInclude, "[Include] attribute on member"); } // Success: persistent name (from attribute or normal member name) var prevName = memberInfo.GetCustomAttribute <PreviousNameAttribute>(); if (prevName != null) { memberConfig.PersistentName = prevName.Name; //VerifyName(attrib.Name); //foreach (var n in attrib.AlternativeNames) // VerifyName(n); } }