// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using log4net; namespace Core.Common.Gui.PropertyBag { /// /// This class represents a single property. /// public class PropertySpec { private static readonly ILog log = LogManager.GetLogger(typeof(PropertySpec)); private readonly PropertyInfo propertyInfo; /// /// Initializes a new instance of the class for a given /// property meta-data object. /// /// The property information. /// Thrown when is /// an index property. /// When is null. public PropertySpec(PropertyInfo propertyInfo) { if (propertyInfo == null) { throw new ArgumentNullException("propertyInfo"); } if (propertyInfo.GetIndexParameters().Length > 0) { throw new ArgumentException(@"Index properties are not allowed.", "propertyInfo"); } this.propertyInfo = propertyInfo; Name = propertyInfo.Name; TypeName = propertyInfo.PropertyType.AssemblyQualifiedName; var attributeList = Attribute.GetCustomAttributes(propertyInfo, true).ToList(); if (propertyInfo.GetSetMethod() == null) { attributeList.Add(new ReadOnlyAttribute(true)); } Attributes = attributeList.ToArray(); } /// /// Gets or sets a collection of additional s for this property. /// This can be used to specify attributes beyond those supported intrinsically by the /// class, such as /// and . /// public Attribute[] Attributes { get; private set; } /// /// Gets the name of the property. /// public string Name { get; private set; } /// /// Gets the fully qualified name of the type of this property. /// public string TypeName { get; private set; } /// /// Sets the property represented by this instance of some object instance. /// /// The instance to be updated. /// The new value for the property. /// Thrown when /// /// Represented property is an index-property. /// does not match the target type. /// Property is an instance property but is null. /// is of incorrect type. /// An error occurred while setting the property value. The /// property indicates the reason for the error. /// /// Calling this method while property /// has no setter. /// Calling the method resulted in an exception. /// Thrown when is null /// or the method is not defined on . public void SetValue(object instance, object newValue) { var setMethodInfo = propertyInfo.GetSetMethod(); if (setMethodInfo == null) { throw new InvalidOperationException("Property lacks public setter!"); } setMethodInfo.Invoke(instance, new[] { newValue }); } /// /// Gets the property value represented by this instance of some object instance. /// /// The instance that holds the property to be retrieved. /// The property value on . /// Thrown when /// /// Represented property is an index-property. /// does not match the target type. /// Property is an instance property but is null. /// An error occurred while setting the property value. The /// property indicates the reason for the error. /// /// Thrown when calling this method while /// property has no getter. public object GetValue(object instance) { var getMethodInfo = propertyInfo.GetGetMethod(); if (getMethodInfo == null) { throw new InvalidOperationException("Property lacks public getter!"); } try { return getMethodInfo.Invoke(instance, new object[0]); } catch (TargetException e) { object type = instance == null ? null : instance.GetType(); var message = string.Format(CultureInfo.CurrentCulture, "Are you calling GetValue on the correct instance? Expected '{0}', but was '{1}'", propertyInfo.DeclaringType, type); throw new ArgumentException(message, "instance", e); } catch (TargetInvocationException e) { throw new ArgumentException(@"Something went wrong while getting property; Check InnerException for more information.", "instance", e); } } /// /// Determines whether the captured property is decorated with /// that is configured to use . /// /// Returns true if a is declared using /// , false if no match has been found or when /// the type converter inherits from . /// Custom implementations of is /// likely to have behavior that Core.Common.Gui namespace cannot account for. As /// such those properties will be considered not having the expandable object type converter. public bool IsNonCustomExpandableObjectProperty() { var typeConverterAttribute = (TypeConverterAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof(TypeConverterAttribute), true); if (typeConverterAttribute != null) { try { var type = Type.GetType(typeConverterAttribute.ConverterTypeName); if (type != null && typeof(ExpandableObjectConverter) == type) { return true; } } catch (Exception e) { if (e is TargetInvocationException || e is ArgumentException || e is TypeLoadException || e is FileLoadException || e is BadImageFormatException) { log.DebugFormat("Unable to find TypeConverter of type '{0}", typeConverterAttribute.ConverterTypeName); } else { throw; // Not expected exception -> Fail fast } } } return false; } } }