예제 #1
0
            internal AttributedProperty(PropertyInfo property, FirestorePropertyAttribute attribute)
            {
                _propertyInfo = property;
                FirestoreName = attribute.Name ?? property.Name;
                SentinelValue = SentinelValue.FromPropertyAttributes(property);

                // Note that the error messages in here don't use nameof, as we don't have an overload of CheckState accepting three
                // format arguments.
                // TODO: Put that in GAX and use nameof.
                string typeName = property.DeclaringType.FullName;

                GaxPreconditions.CheckState(property.GetIndexParameters().Length == 0,
                                            "{0}.{1} is an indexer, and should not be decorated with FirestorePropertyAttribute.",
                                            typeName, property.Name);

                // Annoyingly, we can't easily check whether the property is static - we have to check the individual methods.
                var getMethod = property.GetGetMethod(nonPublic: true);
                var setMethod = property.GetSetMethod(nonPublic: true);

                GaxPreconditions.CheckState(getMethod == null || !getMethod.IsStatic,
                                            "{0}.{1} is static, and should not be decorated with FirestorePropertyAttribute.",
                                            typeName, property.Name);
                GaxPreconditions.CheckState(setMethod == null || !setMethod.IsStatic,
                                            "{0}.{1} is static, and should not be decorated with FirestorePropertyAttribute.",
                                            typeName, property.Name);
            }
예제 #2
0
        private FirestoreDataAttributedType(BclType type)
        {
            var typeInfo = type.GetTypeInfo();

            _attribute = typeInfo.GetCustomAttribute <FirestoreDataAttribute>(inherit: false);
            // This would be an internal library bug. We shouldn't be calling it in this case.
            GaxPreconditions.CheckState(_attribute != null, "Type {0} is not decorated with {1}.", type.FullName, nameof(FirestoreDataAttribute));

            // The rest are user bugs.
            GaxPreconditions.CheckState(Enum.IsDefined(typeof(UnknownPropertyHandling), UnknownPropertyHandling),
                                        "Type {0} has invalid {1} value", type.FullName, nameof(UnknownPropertyHandling));

            _ctor = typeInfo
                    .GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
                    .SingleOrDefault(ctor => ctor.GetParameters().Length == 0);
            GaxPreconditions.CheckState(_ctor != null, "Type {0} has no parameterless constructor", type.FullName);

            List <AttributedProperty> readableProperties = new List <AttributedProperty>();
            Dictionary <string, AttributedProperty> writableProperties = new Dictionary <string, AttributedProperty>();

            // We look for static properties specifically to find problems. We'll never use static properties.
            foreach (var property in typeInfo.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
            {
                FirestorePropertyAttribute attribute = property.GetCustomAttribute <FirestorePropertyAttribute>(inherit: true);
                if (attribute == null)
                {
                    continue;
                }
                var    attributedProperty = new AttributedProperty(property, attribute);
                string firestoreName      = attributedProperty.FirestoreName;

                // Note that we check readable and writable properties separately. We could theoretically have
                // two separate properties, one read-only and one write-only, with the same name in Firestore.
                if (attributedProperty.CanRead)
                {
                    // This is O(N), but done once per type so should be okay.
                    GaxPreconditions.CheckState(!readableProperties.Any(p => p.FirestoreName == firestoreName),
                                                "Type {0} contains multiple readable properties with name {1}", type.FullName, firestoreName);
                    readableProperties.Add(attributedProperty);
                }
                if (attributedProperty.CanWrite)
                {
                    GaxPreconditions.CheckState(!writableProperties.ContainsKey(firestoreName),
                                                "Type {0} contains multiple writable properties with name {1}", type.FullName, firestoreName);
                    writableProperties[firestoreName] = attributedProperty;
                }
            }
            ReadableProperties = readableProperties.AsReadOnly();
            WritableProperties = new ReadOnlyDictionary <string, AttributedProperty>(writableProperties);
        }