using System;
using System.Reflection;
namespace FullSerializer.Internal {
///
/// A property or field on a MetaType. This unifies the FieldInfo and PropertyInfo classes.
///
public class fsMetaProperty {
internal fsMetaProperty(fsConfig config, FieldInfo field) {
_memberInfo = field;
StorageType = field.FieldType;
MemberName = field.Name;
IsPublic = field.IsPublic;
IsReadOnly = field.IsInitOnly;
CanRead = true;
CanWrite = true;
CommonInitialize(config);
}
internal fsMetaProperty(fsConfig config, PropertyInfo property) {
_memberInfo = property;
StorageType = property.PropertyType;
MemberName = property.Name;
IsPublic = (property.GetGetMethod() != null && property.GetGetMethod().IsPublic) &&
(property.GetSetMethod() != null && property.GetSetMethod().IsPublic);
IsReadOnly = false;
CanRead = property.CanRead;
CanWrite = property.CanWrite;
CommonInitialize(config);
}
private void CommonInitialize(fsConfig config) {
var attr = fsPortableReflection.GetAttribute(_memberInfo);
if (attr != null) {
JsonName = attr.Name;
OverrideConverterType = attr.Converter;
}
if (string.IsNullOrEmpty(JsonName)) {
JsonName = config.GetJsonNameFromMemberName(MemberName, _memberInfo);
}
}
///
/// Internal handle to the reflected member.
///
private MemberInfo _memberInfo;
///
/// The type of value that is stored inside of the property. For example, for an int field,
/// StorageType will be typeof(int).
///
public Type StorageType {
get;
private set;
}
///
/// A custom fsBaseConverter instance to use for this field/property, if requested. This will be
/// null if the default converter selection algorithm should be used. This is specified using the
/// [fsObject] annotation with the Converter field.
///
public Type OverrideConverterType {
get;
private set;
}
///
/// Can this property be read?
///
public bool CanRead {
get;
private set;
}
///
/// Can this property be written to?
///
public bool CanWrite {
get;
private set;
}
///
/// The serialized name of the property, as it should appear in JSON.
///
public string JsonName {
get;
private set;
}
///
/// The name of the actual member.
///
public string MemberName {
get;
private set;
}
///
/// Is this member public?
///
public bool IsPublic {
get;
private set;
}
///
/// Is this type readonly? We can modify readonly properties using reflection, but not
/// using generated C#.
///
public bool IsReadOnly {
get; private set;
}
///
/// Writes a value to the property that this MetaProperty represents, using given object
/// instance as the context.
///
public void Write(object context, object value) {
FieldInfo field = _memberInfo as FieldInfo;
PropertyInfo property = _memberInfo as PropertyInfo;
if (field != null) {
field.SetValue(context, value);
}
else if (property != null) {
MethodInfo setMethod = property.GetSetMethod(/*nonPublic:*/ true);
if (setMethod != null) {
setMethod.Invoke(context, new object[] { value });
}
}
}
///
/// Reads a value from the property that this MetaProperty represents, using the given
/// object instance as the context.
///
public object Read(object context) {
if (_memberInfo is PropertyInfo) {
return ((PropertyInfo)_memberInfo).GetValue(context, new object[] { });
}
else {
return ((FieldInfo)_memberInfo).GetValue(context);
}
}
}
}