Skip to content

Instantly share code, notes, and snippets.

@tugberkugurlu
Last active December 30, 2015 22:09
Show Gist options
  • Save tugberkugurlu/7892276 to your computer and use it in GitHub Desktop.
Save tugberkugurlu/7892276 to your computer and use it in GitHub Desktop.
Type description (object graph) discoveribility through reflection.
public class PersonRequestModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class PersonDto
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public Nullable<int> Score { get; set; }
public IEnumerable<Point> Points { get; set; }
public IEnumerable<string> Tags { get; set; }
public AddressDto Address { get; set; }
public DateTimeOffset CreatedOn { get; set; }
}
public class Point
{
public double Value { get; set; }
public string RatedBy { get; set; }
}
public class AddressDto
{
public int Id { get; set; }
public string Address { get; set; }
public LocationDto Location { get; set; }
}
public class LocationDto
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
class Program
{
static void Main(string[] args)
{
IDictionary<string, string> descs = FlattenAsDictionary(typeof(PersonDto));
foreach (KeyValuePair<string, string> desc in descs)
{
Console.WriteLine(desc);
}
/*
*
Result:
[Address.Location.Latitude, Latitude - System.Double]
[Address.Location.Longitude, Longitude - System.Double]
[Address.Id, Id - System.Int32]
[Address.Address, Address - System.String]
[Points[0].Value, Value - System.Double]
[Points[0].RatedBy, RatedBy - System.String]
[Id, Id - System.Int32]
[FirstName, FirstName - System.String]
[LastName, LastName - System.String]
[Age, Age - System.Int32]
[Score, Score - System.Int32]
[Tags, Tags - System.String]
[CreatedOn, CreatedOn - System.DateTimeOffset]
*
*/
}
static IDictionary<string, string> FlattenAsDictionary(Type type, string prefix = null)
{
IEnumerable<PropertyInfo> properties = type.GetProperties();
Dictionary<string, string> tempStorage = new Dictionary<string, string>();
foreach (PropertyInfo property in properties)
{
string propertyName = (prefix == null)
? property.Name
: string.Concat(prefix, ".", property.Name);
Type propertyType = TypeHelper.IsNullableValueType(property.PropertyType)
? Nullable.GetUnderlyingType(property.PropertyType)
: property.PropertyType;
if (TypeHelper.IsSimpleType(propertyType))
{
string desc = property.Name + " - " + propertyType.FullName;
tempStorage.Add(propertyName, desc);
}
else if(TypeHelper.IsCollection(propertyType))
{
Type enumerableType = TypeHelper.GetEnumerableType(propertyType);
if (TypeHelper.IsSimpleType(enumerableType))
{
string desc = property.Name + " - " + enumerableType.FullName;
tempStorage.Add(propertyName, desc);
}
else
{
propertyName = propertyName + "[0]";
IDictionary<string, string> innerDescs = FlattenAsDictionary(enumerableType, propertyName);
tempStorage = innerDescs.Concat(tempStorage).ToDictionary(x => x.Key, x => x.Value);
}
}
else
{
IDictionary<string, string> innerDescs = FlattenAsDictionary(propertyType, propertyName);
tempStorage = innerDescs.Concat(tempStorage).ToDictionary(x => x.Key, x => x.Value);
}
}
return tempStorage;
}
}
public static class TypeHelper
{
internal static bool IsNullableValueType(Type type)
{
return Nullable.GetUnderlyingType(type) != null;
}
internal static bool IsSimpleType(Type type)
{
return type.IsPrimitive ||
type.Equals(typeof(string)) ||
type.Equals(typeof(DateTime)) ||
type.Equals(typeof(Decimal)) ||
type.Equals(typeof(Guid)) ||
type.Equals(typeof(DateTimeOffset)) ||
type.Equals(typeof(TimeSpan));
}
internal static bool IsSimpleUnderlyingType(Type type)
{
Type underlyingType = Nullable.GetUnderlyingType(type);
if (underlyingType != null)
{
type = underlyingType;
}
return TypeHelper.IsSimpleType(type);
}
internal static bool IsCollection(Type type)
{
Type genericParam = GetEnumerableType(type);
return IsSimpleType(type) ? false : genericParam != null;
}
/// <remarks>
/// ref: http://stackoverflow.com/questions/1846671/determine-if-collection-is-of-type-ienumerablet
/// </remarks>
internal static Type GetEnumerableType(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return type.GetGenericArguments()[0];
}
foreach (Type intType in type.GetInterfaces())
{
if (intType.IsGenericType && intType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return intType.GetGenericArguments()[0];
}
}
return null;
}
/// <summary>
/// </summary>
/// <see href="http://stackoverflow.com/questions/11430654/is-it-possible-to-use-type-gettype-with-a-dynamically-loaded-assembly" />
/// <param name="assemblyQualifiedName"></param>
/// <returns></returns>
/// <exception cref="System.TypeLoadException">
/// throwOnError is true and the type is not found. -or-throwOnError is true
/// and typeName contains invalid characters, such as an embedded tab.-or-throwOnError
/// is true and typeName is an empty string.-or-throwOnError is true and typeName
/// represents an array type with an invalid size. -or-typeName represents an
/// array of System.TypedReference.
/// </exception>
internal static Type ParseAssemblyQualifiedName(string assemblyQualifiedName)
{
// Throws exception is type was not found
Type type = Type.GetType(assemblyQualifiedName,
(name) =>
{
// Returns the assembly of the type by enumerating loaded assemblies
// in the app domain
return AppDomain.CurrentDomain.GetAssemblies().Where(z => z.FullName == name.FullName).FirstOrDefault();
},
null,
true);
return type;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment