/* Copyright 2010-present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace MongoDB.Bson.Serialization.Conventions { /// /// A convention that finds the id member by name. /// public class NamedIdMemberConvention : ConventionBase, IClassMapConvention { // private fields private readonly IEnumerable _names; private readonly MemberTypes _memberTypes; private readonly BindingFlags _bindingFlags; // constructors /// /// Initializes a new instance of the class. /// /// The names. public NamedIdMemberConvention(params string[] names) : this((IEnumerable)names) { } /// /// Initializes a new instance of the class. /// /// The names. public NamedIdMemberConvention(IEnumerable names) : this(names, BindingFlags.Instance | BindingFlags.Public) { } /// /// Initializes a new instance of the class. /// /// The names. /// The member types. public NamedIdMemberConvention(IEnumerable names, MemberTypes memberTypes) : this(names, memberTypes, BindingFlags.Instance | BindingFlags.Public) { } /// /// Initializes a new instance of the class. /// /// The names. /// The binding flags. public NamedIdMemberConvention(IEnumerable names, BindingFlags bindingFlags) : this(names, MemberTypes.Field | MemberTypes.Property, bindingFlags) { } /// /// Initializes a new instance of the class. /// /// The names. /// The member types. /// The binding flags. /// public NamedIdMemberConvention(IEnumerable names, MemberTypes memberTypes, BindingFlags bindingFlags) { if (names == null) { throw new ArgumentNullException("names"); } _names = names; _memberTypes = memberTypes; _bindingFlags = bindingFlags | BindingFlags.DeclaredOnly; } // public methods /// /// Applies a modification to the class map. /// /// The class map. public void Apply(BsonClassMap classMap) { var classTypeInfo = classMap.ClassType.GetTypeInfo(); foreach (var name in _names) { var member = classTypeInfo.GetMember(name, _memberTypes, _bindingFlags).SingleOrDefault(); if (member != null) { if (IsValidIdMember(classMap, member)) { classMap.MapIdMember(member); return; } } } } private bool IsValidIdMember(BsonClassMap classMap, MemberInfo member) { if (member is PropertyInfo) { var getMethodInfo = ((PropertyInfo)member).GetMethod; if (getMethodInfo.IsVirtual && getMethodInfo.GetBaseDefinition().DeclaringType != classMap.ClassType) { return false; } } return true; } } }