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

Вильданов Савелий #218

Open
wants to merge 5 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
9 changes: 9 additions & 0 deletions ObjectPrinting/ObjectExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ObjectPrinting;

public static class ObjectExtensions
{
public static string PrintToString<T>(this T obj)
{
return ObjectPrinter.For<T>().PrintToString(obj);
}
}
1 change: 1 addition & 0 deletions ObjectPrinting/ObjectPrinting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
Expand Down
175 changes: 163 additions & 12 deletions ObjectPrinting/PrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace ObjectPrinting
{
public class PrintingConfig<TOwner>
{
private readonly HashSet<Type> excludedTypes = new();
private readonly HashSet<PropertyInfo> excludedFields = new();
private readonly HashSet<object> proccesedObjects = new();
private readonly Dictionary<Type, Func<object, string>> alternativeSerializeTypes = new();
private readonly Dictionary<PropertyInfo, Func<object, string>> alternativeSerializeProperties = new();
private readonly Dictionary<Type, CultureInfo> alternativeCulture = new();
private readonly Dictionary<PropertyInfo, int> lengthOfProperties = new();

private readonly Type[] finalTypes =
{
typeof(int), typeof(double), typeof(float), typeof(string),
typeof(DateTime), typeof(TimeSpan), typeof(Guid)
};

public string PrintToString(TOwner obj)
{
return PrintToString(obj, 0);
Expand All @@ -14,28 +33,160 @@ public string PrintToString(TOwner obj)
private string PrintToString(object obj, int nestingLevel)

Choose a reason for hiding this comment

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

Что-то не так с алгоритмом: у нас есть метод CheckSerializationConditions и логика в нём частично повторяется тут. Мб как-то можно более проще сделать?

{
//TODO apply configurations
var indentation = new string('\t', nestingLevel + 1);

var specialSerialization = TryGetSerializationString(obj, nestingLevel);
if (specialSerialization != null)
return specialSerialization;

proccesedObjects.Add(obj);
var sb = new StringBuilder();
var type = obj.GetType();
sb.AppendLine(type.Name);
foreach (var propertyInfo in type.GetProperties())
{
string property = indentation + propertyInfo.Name + " = ";
if (excludedTypes.Contains(propertyInfo.PropertyType) || excludedFields.Contains(propertyInfo))
continue;
if (lengthOfProperties.TryGetValue(propertyInfo, out var length))
{
var substring = propertyInfo.GetValue(obj).ToString().Substring(0, length);
sb.Append(property + substring + Environment.NewLine);
continue;
}

string serializedObj;
if (alternativeSerializeProperties.TryGetValue(propertyInfo, out var propertyFunc))
serializedObj = property + propertyFunc(propertyInfo.GetValue(obj)) + Environment.NewLine;
else
serializedObj = property + PrintToString(propertyInfo.GetValue(obj), nestingLevel + 1);

sb.Append(serializedObj);
}

return sb.ToString();
}


private string TryGetSerializationString(object? obj, int nestingLevel)
{
if (obj == null)
return "null" + Environment.NewLine;
if (excludedTypes.Contains(obj.GetType()))
return string.Empty;
if (proccesedObjects.Contains(obj))
return "Cyclic reference" + Environment.NewLine;
if (alternativeSerializeTypes.TryGetValue(obj.GetType(), out var serializeFunc))
return serializeFunc(obj) + Environment.NewLine;

var finalTypes = new[]
{
typeof(int), typeof(double), typeof(float), typeof(string),
typeof(DateTime), typeof(TimeSpan)
};
if (obj is IFormattable formObj && alternativeCulture.TryGetValue(obj.GetType(), out var newCulture))
return formObj.ToString("N", newCulture) + Environment.NewLine;
if (finalTypes.Contains(obj.GetType()))
return obj + Environment.NewLine;
if (obj is IDictionary dictionary)
return PrintDictionary(dictionary, nestingLevel);
if (obj is IEnumerable collection)
return PrintCollection(collection, nestingLevel);

return null;
}

var identation = new string('\t', nestingLevel + 1);
private string PrintCollection(IEnumerable collection, int nestingLevel)
{
var sb = new StringBuilder();
var type = obj.GetType();
sb.AppendLine(type.Name);
foreach (var propertyInfo in type.GetProperties())
var indentation = new string('\t', nestingLevel + 1);

sb.Append(indentation + collection.GetType().Name + "{" + Environment.NewLine);
int index = 0;
foreach (var item in collection)
{
sb.Append(identation + propertyInfo.Name + " = " +
PrintToString(propertyInfo.GetValue(obj),
nestingLevel + 1));
sb.Append(indentation + "\t[" + index + "] = ");
sb.Append(GetStringWithNestingLevel(item, nestingLevel + 2).Trim());
sb.Append(Environment.NewLine);
index++;
}

sb.Append(indentation + "}");
return sb.ToString();
}

private string PrintDictionary(IDictionary dictionary, int nestingLevel)
{
var sb = new StringBuilder();
var indentation = new string('\t', nestingLevel + 1);
sb.Append(indentation + dictionary.GetType().Name + "{" + Environment.NewLine);
foreach (DictionaryEntry element in dictionary)
{
var key = GetStringWithNestingLevel(element.Key, nestingLevel + 1);
var value = GetStringWithNestingLevel(element.Value, nestingLevel + 2).Trim();
sb.Append(key + " : " + value + Environment.NewLine);
}

sb.Append(indentation + "}");
return sb.ToString();
}

private string GetStringWithNestingLevel(object obj, int nestingLevel)
{
var indentation = new string('\t', nestingLevel + 1);
if (finalTypes.Contains(obj.GetType()))
return indentation + obj;
var result = PrintToString(obj, nestingLevel);
return Environment.NewLine + indentation + result;
}

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

public PrintingConfig<TOwner> Exclude<T>(Expression<Func<TOwner, T>> func)
{
var propertyInfo = GetPropertyInfo(func);
excludedFields.Add(propertyInfo);
return this;
}

public PropertyPrintingConfig<TOwner, TPrintType> Printing<TPrintType>()
{
return new PropertyPrintingConfig<TOwner, TPrintType>(this, null);
}

public PropertyPrintingConfig<TOwner, TPropType> Printing<TPropType>(
Expression<Func<TOwner, TPropType>> func)
{
var propertyInfo = GetPropertyInfo(func);
return new PropertyPrintingConfig<TOwner, TPropType>(this, propertyInfo);
}

private PropertyInfo GetPropertyInfo<T>(Expression<Func<TOwner, T>> propertyExpression)
{
var propertyName = ((MemberExpression) propertyExpression.Body).Member.Name;
var propertyInfo = typeof(TOwner).GetProperty(propertyName);
if (propertyInfo == null)
throw new Exception($"Property {propertyName} could not be found.");
return propertyInfo;
}

internal void AddSerializedProperty<T>(PropertyInfo propertyInfo, Func<T, string> serializeFunc)
{
alternativeSerializeProperties[propertyInfo] = o => serializeFunc((T) o);
}

internal void AddLengthOfProperty(PropertyInfo propertyInfo, int length)
{
lengthOfProperties[propertyInfo] = length;
}

internal void AddAlternativeCulture(Type type, CultureInfo cultureInfo)
{
alternativeCulture[type] = cultureInfo;
}

internal void AddSerializedType<T>(Func<T, string> serializeFunc)
{
alternativeSerializeTypes[typeof(T)] = o => serializeFunc((T) o);
}
}
}
41 changes: 41 additions & 0 deletions ObjectPrinting/PropertyPrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Globalization;
using System.Reflection;

namespace ObjectPrinting;

public class PropertyPrintingConfig<TOwner, TPropType>
{
internal PrintingConfig<TOwner> PrintingConfig { get; }
internal readonly PropertyInfo? PropertyInfo;


public PropertyPrintingConfig(PrintingConfig<TOwner> printingConfig, PropertyInfo propertyInfo)
{
PrintingConfig = printingConfig;
PropertyInfo = propertyInfo;
}

public PrintingConfig<TOwner> Using(Func<TPropType, string> newSerialize)
{
return PropertyInfo == null ? SetSerializedType(newSerialize) : SetSerializedProp(newSerialize);
}

public PrintingConfig<TOwner> Using(CultureInfo cultureInfo)
{
PrintingConfig.AddAlternativeCulture(typeof(TPropType), cultureInfo);
return PrintingConfig;
}

private PrintingConfig<TOwner> SetSerializedProp(Func<TPropType, string> newSerialize)
{
PrintingConfig.AddSerializedProperty(PropertyInfo!, newSerialize);
return PrintingConfig;
}

private PrintingConfig<TOwner> SetSerializedType(Func<TPropType, string> newSerialize)
{
PrintingConfig.AddSerializedType(newSerialize);
return PrintingConfig;
}
}
15 changes: 15 additions & 0 deletions ObjectPrinting/PropertyPrintingConfigExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;


namespace ObjectPrinting;

public static class PropertyPrintingConfigExtensions
{
public static PrintingConfig<TOwner> TrimmedToLength<TOwner>(
this PropertyPrintingConfig<TOwner, string> propertyConfig,
int maxLen)
{
propertyConfig.PrintingConfig.AddLengthOfProperty(propertyConfig.PropertyInfo, maxLen);
return propertyConfig.PrintingConfig;
}
}
27 changes: 0 additions & 27 deletions ObjectPrinting/Tests/ObjectPrinterAcceptanceTests.cs

This file was deleted.

12 changes: 0 additions & 12 deletions ObjectPrinting/Tests/Person.cs

This file was deleted.

Loading