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

Волков Кирилл #199

Open
wants to merge 6 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
48 changes: 48 additions & 0 deletions ObjectPrinting/Extensions/EnumerableExtensions.cs
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 comment was marked as resolved.

this IEnumerable<T> enumerable,
string startSymbol,
string endSymbol,
Func<T, string> getRow,

This comment was marked as resolved.

ImmutableList<object> previous)

This comment was marked as resolved.

{
var sb = new StringBuilder();
sb.AppendLine(startSymbol);

var identation = new string('\t', previous.Count);

This comment was marked as resolved.


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();
}
}
29 changes: 29 additions & 0 deletions ObjectPrinting/Extensions/IDictionaryExtensions.cs
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.

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.

{
foreach (DictionaryEntry entry in dictionary)
yield return entry;
}
}
14 changes: 14 additions & 0 deletions ObjectPrinting/Extensions/ObjectExtensions.cs
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);
}
}
11 changes: 11 additions & 0 deletions ObjectPrinting/ISerializer.cs
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.


namespace ObjectPrinting
{
public interface ISerializer<out T, TOwner>
{
public PrintingConfig<TOwner> PrintingConfig { get; }
public PrintingConfig<TOwner> Serialize(Func<T, string> serializer);
}
}
10 changes: 10 additions & 0 deletions ObjectPrinting/ISerializerSetter.cs
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.

{
public void SetSerializer<T>(Func<T, string> serializer, PropertyInfo propertyInfo);
}
}
7 changes: 1 addition & 6 deletions ObjectPrinting/ObjectPrinting.csproj
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.


<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>
185 changes: 155 additions & 30 deletions ObjectPrinting/PrintingConfig.cs
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.

{
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.

{
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;
}
}
29 changes: 29 additions & 0 deletions ObjectPrinting/Serializer.cs
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.

{
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;
}
}
}
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.

Loading