-
Notifications
You must be signed in to change notification settings - Fork 214
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
Волков Кирилл #199
base: master
Are you sure you want to change the base?
Волков Кирилл #199
Changes from 2 commits
948ccb9
0264935
045edec
e046be5
e75c828
5e076d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System.Text; | ||
|
||
namespace ObjectPrinting.Extensions; | ||
|
||
public static class EnumerableExtensions | ||
{ | ||
public static string ObjectPrintEnumerable<T>( | ||
this IEnumerable<object> enumerable, | ||
PrintingConfig<T> printingConfig, | ||
ImmutableList<object> previous) | ||
{ | ||
|
||
previous = previous.Add(enumerable); | ||
|
||
return enumerable.EnumerateForObjectPrinting( | ||
"[", "]", | ||
obj => $"{printingConfig.PrintToString1(obj, previous)},", | ||
previous); | ||
} | ||
|
||
public static string EnumerateForObjectPrinting<T>( | ||
this IEnumerable<T> enumerable, | ||
string startSymbol, | ||
string endSymbol, | ||
Func<T, string> getRow, | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
ImmutableList<object> previous) | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
{ | ||
var sb = new StringBuilder(); | ||
sb.AppendLine(startSymbol); | ||
|
||
var identation = new string('\t', previous.Count); | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
|
||
foreach (var obj in enumerable) | ||
{ | ||
sb.Append(identation); | ||
sb.AppendLine(getRow(obj)); | ||
} | ||
|
||
sb.Append(new string('\t', previous.Count - 1)); | ||
sb.Append(endSymbol); | ||
|
||
return sb.ToString(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
|
||
namespace ObjectPrinting.Extensions; | ||
|
||
public static class DictionaryExtensions | ||
{ | ||
public static string ObjectPrintDictionary<T>( | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
this IDictionary dictionary, | ||
PrintingConfig<T> printingConfig, | ||
ImmutableList<object> previous) | ||
{ | ||
previous = previous.Add(dictionary); | ||
|
||
return dictionary | ||
.KeysToValues() | ||
.EnumerateForObjectPrinting( | ||
"{", "}", | ||
pair => $"{pair.Key}: {printingConfig.PrintToString1(pair.Value, previous)};", | ||
previous); | ||
} | ||
|
||
private static IEnumerable<DictionaryEntry> KeysToValues(this IDictionary dictionary) | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
{ | ||
foreach (DictionaryEntry entry in dictionary) | ||
yield return entry; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
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<T>(this T obj, PrintingConfig<T> printingConfig) | ||
{ | ||
return printingConfig.PrintToString(obj); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using System; | ||
using System.Globalization; | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
|
||
namespace ObjectPrinting | ||
{ | ||
public interface ISerializer<out T, TOwner> | ||
{ | ||
public PrintingConfig<TOwner> PrintingConfig { get; } | ||
public PrintingConfig<TOwner> Serialize(Func<T, string> serializer); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using System; | ||
using System.Reflection; | ||
|
||
namespace ObjectPrinting | ||
{ | ||
public interface ISerializerSetter | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
{ | ||
public void SetSerializer<T>(Func<T, string> serializer, PropertyInfo propertyInfo); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
|
||
<PropertyGroup> | ||
<LangVersion>8</LangVersion> | ||
<LangVersion>latest</LangVersion> | ||
<TargetFramework>netcoreapp3.1</TargetFramework> | ||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> | ||
<PackageReference Include="NUnit" Version="3.12.0" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,166 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Globalization; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using System.Text; | ||
using ObjectPrinting.Extensions; | ||
|
||
namespace ObjectPrinting | ||
namespace ObjectPrinting; | ||
|
||
public class PrintingConfig<TOwner> : ISerializerSetter | ||
{ | ||
public class PrintingConfig<TOwner> | ||
private readonly Dictionary<Type, Func<object, string>> typeSerializers = new(); | ||
private readonly Dictionary<PropertyInfo, Func<object, string>> propertySerializers = new(); | ||
|
||
private readonly HashSet<PropertyInfo> excludedProps = new(); | ||
private readonly HashSet<Type> excludedTypes = new(); | ||
|
||
public PrintingConfig<TOwner> Exclude<T>() | ||
{ | ||
public string PrintToString(TOwner obj) | ||
{ | ||
return PrintToString(obj, 0); | ||
} | ||
excludedTypes.Add(typeof(T)); | ||
return this; | ||
} | ||
|
||
public PrintingConfig<TOwner> Exclude<T>(Expression<Func<TOwner, T>> expression) | ||
{ | ||
excludedProps.Add(GetPropertyInfoFromExpression(expression)); | ||
return this; | ||
} | ||
|
||
public ISerializer<T, TOwner> Select<T>() | ||
{ | ||
return new Serializer<T, TOwner>(this); | ||
} | ||
|
||
public ISerializer<T, TOwner> Select<T>(Expression<Func<TOwner, T>> expression) | ||
{ | ||
return new Serializer<T, TOwner>(this, GetPropertyInfoFromExpression(expression)); | ||
} | ||
|
||
public PrintingConfig<TOwner> SetCulture<T>(CultureInfo cultureInfo) | ||
where T: IFormattable | ||
{ | ||
return Select<T>() | ||
.Serialize(obj => string.Format(cultureInfo, "{0}", obj)); | ||
} | ||
|
||
public PrintingConfig<TOwner> SetCulture<T>(Expression<Func<TOwner, T>> expression, CultureInfo cultureInfo) | ||
where T: IFormattable | ||
{ | ||
return Select(expression) | ||
.Serialize(obj => string.Format(cultureInfo, "{0}", obj)); | ||
} | ||
|
||
public PrintingConfig<TOwner> SliceStrings(int maxLength) | ||
{ | ||
if (maxLength <= 0) | ||
throw new ArgumentException("Parameter maxLength must be positive"); | ||
|
||
return Select<string>() | ||
.Serialize(s => maxLength >= s.Length ? s : s[..maxLength]); | ||
} | ||
|
||
void ISerializerSetter.SetSerializer<T>(Func<T, string> serializer, PropertyInfo propertyInfo) | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
{ | ||
if (propertyInfo is not null) | ||
propertySerializers[propertyInfo] = obj => serializer((T) obj); | ||
else | ||
typeSerializers[typeof(T)] = obj => serializer((T) obj); | ||
} | ||
|
||
public string PrintToString(TOwner obj) | ||
{ | ||
return PrintToString1(obj, new List<object>().ToImmutableList()); | ||
} | ||
|
||
public string PrintToString1(object obj, ImmutableList<object> previous) | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
{ | ||
if (obj == null) | ||
return "null"; | ||
|
||
var type = obj.GetType(); | ||
|
||
private string PrintToString(object obj, int nestingLevel) | ||
if (TrySerializeValueType(type, obj, out var serializedValue)) | ||
return serializedValue; | ||
|
||
if (IsCyclic(obj, previous)) | ||
return "cyclic link"; | ||
|
||
if (obj is IDictionary dictionary) | ||
return dictionary.ObjectPrintDictionary(this, previous); | ||
|
||
if (obj is IEnumerable enumerable) | ||
return enumerable.Cast<object>().ObjectPrintEnumerable(this, previous); | ||
|
||
var identation = new string('\t', previous.Count + 1); | ||
previous = previous.Add(obj); | ||
var sb = new StringBuilder(); | ||
sb.AppendLine(type.Name + " ("); | ||
|
||
foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) | ||
{ | ||
//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())) | ||
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()) | ||
{ | ||
sb.Append(identation + propertyInfo.Name + " = " + | ||
PrintToString(propertyInfo.GetValue(obj), | ||
nestingLevel + 1)); | ||
} | ||
return sb.ToString(); | ||
if (IsExcluded(property)) | ||
continue; | ||
|
||
sb.Append($"{identation}{property.Name}: "); | ||
|
||
if (TrySerializeProperty(obj, property, out var serialized)) | ||
sb.Append(serialized); | ||
else | ||
sb.Append(PrintToString1(property.GetValue(obj), previous)); | ||
|
||
sb.AppendLine(";"); | ||
} | ||
|
||
sb.Append(new string('\t', previous.Count - 1) + ")"); | ||
|
||
return sb.ToString(); | ||
} | ||
|
||
private bool TrySerializeValueType(Type type, object obj, out string serialized) | ||
{ | ||
serialized = ""; | ||
|
||
if (obj is not string && !type.IsValueType) | ||
return false; | ||
|
||
serialized = typeSerializers.TryGetValue(type, out var serializer) | ||
? serializer(obj) | ||
: obj.ToString(); | ||
|
||
return true; | ||
} | ||
|
||
private bool IsCyclic(object current, IEnumerable<object> previous) | ||
{ | ||
return previous.Any(e => ReferenceEquals(e, current)); | ||
} | ||
|
||
private bool IsExcluded(PropertyInfo propertyInfo) | ||
{ | ||
return excludedProps.Contains(propertyInfo) || excludedTypes.Contains(propertyInfo.PropertyType); | ||
} | ||
|
||
private bool TrySerializeProperty(object obj, PropertyInfo propertyInfo, out string serialized) | ||
{ | ||
serialized = ""; | ||
|
||
if (!propertySerializers.TryGetValue(propertyInfo, out var serializer)) | ||
return false; | ||
|
||
serialized = serializer(propertyInfo.GetValue(obj)); | ||
return true; | ||
} | ||
|
||
private PropertyInfo GetPropertyInfoFromExpression<T>(Expression<Func<TOwner, T>> expression) | ||
{ | ||
if (expression.Body is not MemberExpression memberExpression) | ||
throw new ArgumentException($"Expression {expression} is not MemberExpression"); | ||
|
||
return memberExpression.Member as PropertyInfo; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using System; | ||
using System.Reflection; | ||
|
||
namespace ObjectPrinting | ||
{ | ||
public class Serializer<T, TOwner> : ISerializer<T, TOwner> | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
{ | ||
public PrintingConfig<TOwner> PrintingConfig { get; } | ||
private readonly PropertyInfo propertyInfo; | ||
|
||
public Serializer(PrintingConfig<TOwner> printingConfig, PropertyInfo propertyInfo) | ||
{ | ||
PrintingConfig = printingConfig; | ||
this.propertyInfo = propertyInfo; | ||
} | ||
|
||
public Serializer(PrintingConfig<TOwner> printingConfig) | ||
{ | ||
PrintingConfig = printingConfig; | ||
} | ||
|
||
public PrintingConfig<TOwner> Serialize(Func<T, string> serializer) | ||
{ | ||
(PrintingConfig as ISerializerSetter).SetSerializer(serializer, propertyInfo); | ||
|
||
return PrintingConfig; | ||
} | ||
} | ||
} |
This file was deleted.
This file was deleted.
This comment was marked as resolved.
Sorry, something went wrong.