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 2 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
126 changes: 112 additions & 14 deletions ObjectPrinting/PrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,139 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using ObjectPrinting.Extensions;

namespace ObjectPrinting
{
public class PrintingConfig<TOwner>
{
public string PrintToString(TOwner obj)
private readonly HashSet<Type> finalTypes = new HashSet<Type>
{
return PrintToString(obj, 0);
typeof(int), typeof(double), typeof(float),
typeof(bool), typeof(long), typeof(string),
typeof(DateTime), typeof(TimeSpan), typeof(Guid)
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А как же остальные простые типы? Например, uint, decimal и тд?

На самом деле есть более простой способ узнать, является ли тип простым, не перечисляя все числовые вариации. Небольшая подсказка: посмотри в сторону Type


private readonly HashSet<MemberInfo> excludedMembers = new HashSet<MemberInfo>();
private readonly HashSet<Type> excludedTypes = new HashSet<Type>();
private readonly HashSet<object> serializedObjects = new HashSet<object>();

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

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

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

public PrintingConfig<TOwner> ExcludeProperty<TProperty>(Expression<Func<TOwner, TProperty>> memberSelector)
{
excludedMembers.Add(((MemberExpression)memberSelector.Body).Member);
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;
return new PrintingPropertyConfig<TOwner, TPropType>(this, memberSerializers, body.Member);
}

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

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

if (!serializedObjects.Add(obj))
return "Cycle, object was already serialized." + Environment.NewLine;

var identation = new string('\t', nestingLevel + 1);
return obj switch
{
IList collection => SerializeCollection(collection, nestingLevel),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кажется, что проверять на список по интерфейсу IList не очень хорошая идея, так как есть ещё более базовые коллекции, которые не будут сериализованы, так как не наследуют IList

IDictionary dictionary => SerializeDictionary(dictionary, nestingLevel),
_ => SerializeObject(obj, nestingLevel)
};
}

private string SerializeCollection(IList collection, int nestingLevel)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Давай вытащим конкретные кейсы сериализации в отдельный класс-утилиту для сериализации

{
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();
}

private string SerializeDictionary(IDictionary dictionary, int nestingLevel)
{
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();
}

private string SerializeObject(object obj, int nestingLevel)
{
var indent = new string('\t', nestingLevel + 1);
var sb = new StringBuilder();
var type = obj.GetType();
sb.AppendLine(type.Name);
foreach (var propertyInfo in type.GetProperties())
foreach (var memberInfo in type.GetMembers(BindingFlags.Public | BindingFlags.Instance)
.Where(t => t.MemberType == MemberTypes.Field || t.MemberType == MemberTypes.Property)
.Where(x => !IsMemberExcluded(x)))
{
sb.Append(identation + propertyInfo.Name + " = " +
PrintToString(propertyInfo.GetValue(obj),
nestingLevel + 1));
sb.Append(
indent + memberInfo.Name + " = " +
SerializeMember(obj, memberInfo, nestingLevel + 1)
);
}

return sb.ToString();
}

private string SerializeMember(object obj, MemberInfo memberInfo, int nestingLevel)
{
return TryGetCustomSerializer(memberInfo, out var serializer)
? serializer.Invoke(memberInfo.GetValue(obj)) + Environment.NewLine
: PrintToString(memberInfo.GetValue(obj), nestingLevel);
}

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

private bool IsMemberExcluded(MemberInfo memberInfo)
{
return excludedMembers.Contains(memberInfo) ||
excludedTypes.Contains(memberInfo.GetMemberType());
}
}
}
}
28 changes: 28 additions & 0 deletions ObjectPrinting/PrintingPropertyConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Reflection;

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

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

public PrintingConfig<TOwner> To(Func<TProperty, string> serializeRule)
{
serializers[memberInfo] = x => serializeRule((TProperty)x);
return printingConfig;
}
}
}
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.

32 changes: 0 additions & 32 deletions ObjectPrinting/Solved/PropertyPrintingConfig.cs

This file was deleted.

18 changes: 0 additions & 18 deletions ObjectPrinting/Solved/PropertyPrintingConfigExtensions.cs

This file was deleted.

Loading