Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Шевелев Георгий #201

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions ObjectPrinting/Extensions/MemberExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Reflection;

namespace ObjectPrinting.Extensions
{
public static class MemberExtensions
{
internal static Type GetMemberType(this MemberInfo memberInfo) =>
memberInfo.MemberType switch
{
MemberTypes.Property => ((PropertyInfo)memberInfo).PropertyType,
MemberTypes.Field => ((FieldInfo)memberInfo).FieldType,
_ => throw new NotImplementedException($"Getting type of {memberInfo.MemberType} is not implemented")
};

public static object GetValue(this MemberInfo memberInfo, object obj) =>
memberInfo.MemberType switch
{
MemberTypes.Property => ((PropertyInfo)memberInfo).GetValue(obj),
MemberTypes.Field => ((FieldInfo)memberInfo).GetValue(obj),
_ => throw new NotImplementedException($"Getting value of {memberInfo.MemberType} is not implemented")
};
}
}
18 changes: 18 additions & 0 deletions ObjectPrinting/Extensions/ObjectExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace ObjectPrinting.Extensions
{
public static class ObjectExtensions
{
public static string PrintToString<T>(this T obj)
{
return ObjectPrinter.For<T>().PrintToString(obj);
}

public static string PrintToString<TOwner>(this TOwner obj,
Func<PrintingConfig<TOwner>, PrintingConfig<TOwner>> config)
{
return config(ObjectPrinter.For<TOwner>()).PrintToString(obj);
}
}
}
18 changes: 18 additions & 0 deletions ObjectPrinting/Extensions/PrintingPropertyConfigExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Globalization;

namespace ObjectPrinting.Extensions
{
public static class PrintingPropertyConfigExtensions
{
public static PrintingConfig<TOwner> ToTrimmedLength<TOwner>(
this PrintingPropertyConfig<TOwner, string> config, int maxLength) =>
config.To(x => x.Length <= maxLength ? x : x[..maxLength]);

public static PrintingConfig<TOwner> To<TOwner, TPropType>(
this PrintingPropertyConfig<TOwner, TPropType> config, CultureInfo culture) where TPropType : IFormattable
{
return config.To(x => x.ToString(null, culture));
}
}
}
2 changes: 1 addition & 1 deletion ObjectPrinting/ObjectPrinter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace ObjectPrinting
{
public class ObjectPrinter
public static class ObjectPrinter
{
public static PrintingConfig<T> For<T>()
{
Expand Down
95 changes: 74 additions & 21 deletions ObjectPrinting/PrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,94 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using ObjectPrinting.Extensions;

namespace ObjectPrinting
{
public class PrintingConfig<TOwner>
{
public string PrintToString(TOwner obj)
private readonly HashSet<(MemberInfo, int)> excludedMembers = new HashSet<(MemberInfo, int)>();
private readonly HashSet<Type> excludedTypes = new HashSet<Type>();
private readonly HashSet<object> serializedObjects = new HashSet<object>();

private readonly Dictionary<(MemberInfo, int), Func<object, string>> memberSerializers =
new Dictionary<(MemberInfo, int), Func<object, string>>();

public string PrintToString(TOwner obj) => PrintToString(obj, 0);

public PrintingConfig<TOwner> ExcludeProperty<TProperty>()
{
return PrintToString(obj, 0);
excludedTypes.Add(typeof(TProperty));
return this;
}

public PrintingConfig<TOwner> ExcludeProperty<TProperty>(Expression<Func<TOwner, TProperty>> memberSelector)
{
var body = (MemberExpression)memberSelector.Body;
var nestingLevel = body.Expression.ToString().Count(x => x == '.') + 1;
excludedMembers.Add((body.Member, nestingLevel));
return this;
}

public PrintingPropertyConfig<TOwner, TProperty> ChangeSerializationFor<TProperty>() =>
new PrintingPropertyConfig<TOwner, TProperty>(this, memberSerializers, typeof(TProperty));

public PrintingPropertyConfig<TOwner, TPropType> ChangeSerializationFor<TPropType>(
Expression<Func<TOwner, TPropType>> memberSelector)
{
var body = (MemberExpression)memberSelector.Body;
var nestingLevel = body.Expression.ToString().Count(x => x == '.') + 1;
return new PrintingPropertyConfig<TOwner, TPropType>(this, memberSerializers, body.Member, nestingLevel);
}

private string PrintToString(object obj, int nestingLevel)
{
//TODO apply configurations
if (obj == null)
return "null" + Environment.NewLine;

var finalTypes = new[]
var objType = obj.GetType();
if (objType.IsPrimitive || objType.IsValueType || objType == typeof(string))
{
typeof(int), typeof(double), typeof(float), typeof(string),
typeof(DateTime), typeof(TimeSpan)
};
if (finalTypes.Contains(obj.GetType()))
if (memberSerializers.TryGetValue((objType, nestingLevel), out var serializer) ||
memberSerializers.TryGetValue((objType, -1), out serializer) )
return serializer(obj) + Environment.NewLine;
return obj + Environment.NewLine;
}

var identation = new string('\t', nestingLevel + 1);
var sb = new StringBuilder();
var type = obj.GetType();
sb.AppendLine(type.Name);
foreach (var propertyInfo in type.GetProperties())
if (!serializedObjects.Add(obj))
return "Cycle, object was already serialized." + Environment.NewLine;

return obj switch
{
sb.Append(identation + propertyInfo.Name + " = " +
PrintToString(propertyInfo.GetValue(obj),
nestingLevel + 1));
}
return sb.ToString();
IDictionary dictionary =>
SerializerHandler.SerializeDictionary(dictionary, nestingLevel, PrintToString),
IEnumerable enumerable =>
SerializerHandler.SerializeIEnumerable(enumerable, nestingLevel, PrintToString),
_ => SerializerHandler.SerializeObject(obj, nestingLevel, SerializeMember, IsMemberExcluded)
};
}

private bool IsMemberExcluded(MemberInfo memberInfo, int nestingLevel)
{
return excludedMembers.Contains((memberInfo, nestingLevel)) ||
excludedTypes.Contains(memberInfo.GetMemberType());
}

private bool TryGetCustomSerializer(MemberInfo memberInfo, int nestingLevel, out Func<object, string>
serializer)
{
return memberSerializers.TryGetValue((memberInfo, nestingLevel), out serializer) ||
memberSerializers.TryGetValue((memberInfo.GetMemberType(), nestingLevel), out serializer)||
memberSerializers.TryGetValue((memberInfo, -1), out serializer);
}

private string SerializeMember(object obj, MemberInfo memberInfo, int nestingLevel)
{
return TryGetCustomSerializer(memberInfo, nestingLevel, out var serializer)
? serializer.Invoke(memberInfo.GetValue(obj)) + Environment.NewLine
: PrintToString(memberInfo.GetValue(obj), nestingLevel);
}
}
}
}
30 changes: 30 additions & 0 deletions ObjectPrinting/PrintingPropertyConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Reflection;

namespace ObjectPrinting
{
public class PrintingPropertyConfig<TOwner, TProperty>
{
private readonly MemberInfo memberInfo;
private int nestingLevel;
private readonly PrintingConfig<TOwner> printingConfig;
private readonly Dictionary<(MemberInfo, int), Func<object, string>> serializers;

public PrintingPropertyConfig(PrintingConfig<TOwner> printingConfig,
Dictionary<(MemberInfo, int), Func<object, string>> serializers,
MemberInfo memberInfo, int nestingLevel = -1)
{
this.printingConfig = printingConfig;
this.serializers = serializers;
this.memberInfo = memberInfo;
this.nestingLevel = nestingLevel;
}

public PrintingConfig<TOwner> To(Func<TProperty, string> serializeRule)
{
serializers[(memberInfo, nestingLevel)] = x => serializeRule((TProperty)x);
return printingConfig;
}
}
}
61 changes: 61 additions & 0 deletions ObjectPrinting/SerializerHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using System.Text;

namespace ObjectPrinting
{
public static class SerializerHandler
{
public static string SerializeIEnumerable(IEnumerable collection, int nestingLevel,
Func<object, int, string> printToString)
{
var sb = new StringBuilder(collection.GetType().Name + " {" + Environment.NewLine);
foreach (var item in collection)
{
sb.Append(new string('\t', nestingLevel + 1));
sb.Append(printToString(item, nestingLevel + 1));
}

sb.Append(new string('\t', nestingLevel) + '}' + Environment.NewLine);
return sb.ToString();
}

public static string SerializeDictionary(IDictionary dictionary, int nestingLevel,
Func<object, int, string> printToString)
{
var sb = new StringBuilder(dictionary.GetType().Name + " {" + Environment.NewLine);
foreach (var key in dictionary.Keys)
{
sb.Append(new string('\t', nestingLevel + 1));
sb.Append(printToString(key, nestingLevel + 1).Trim() + " = ");
sb.Append(printToString(dictionary[key], nestingLevel + 1));
}

sb.Append(new string('\t', nestingLevel) + '}' + Environment.NewLine);

return sb.ToString();
}

public static string SerializeObject(object obj, int nestingLevel,
Func<object, MemberInfo, int, string> serializeMember, Func<MemberInfo, int, bool> isMemberExcluded)
{
var indent = new string('\t', nestingLevel + 1);
var sb = new StringBuilder();
var type = obj.GetType();
sb.AppendLine(type.Name);
foreach (var memberInfo in type.GetMembers(BindingFlags.Public | BindingFlags.Instance)
.Where(t => t.MemberType == MemberTypes.Field || t.MemberType == MemberTypes.Property)
.Where(x => !isMemberExcluded(x, nestingLevel + 1)))
{
sb.Append(
indent + memberInfo.Name + " = " +
serializeMember(obj, memberInfo, nestingLevel + 1)
);
}

return sb.ToString();
}
}
}
10 changes: 0 additions & 10 deletions ObjectPrinting/Solved/ObjectExtensions.cs

This file was deleted.

10 changes: 0 additions & 10 deletions ObjectPrinting/Solved/ObjectPrinter.cs

This file was deleted.

62 changes: 0 additions & 62 deletions ObjectPrinting/Solved/PrintingConfig.cs

This file was deleted.

Loading