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

Бабин Георгий #191

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
27 changes: 27 additions & 0 deletions ObjectPrinting/Extensions/InnerPrintingConfigExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Globalization;
using ObjectPrinting.InnerPrintingConfig;

namespace ObjectPrinting.Extensions
{
public static class InnerPrintingConfigExtensions
{
public static PrintingConfig<TOwner> Using<TOwner>(this IInnerPrintingConfig<TOwner, double> typeConfig, CultureInfo culture)
{
typeConfig.ParentConfig.TypeSerializers[typeof(double)] = obj => ((double) obj).ToString(culture);
return typeConfig.ParentConfig;
}

public static PrintingConfig<TOwner> Using<TOwner>(this IInnerPrintingConfig<TOwner, DateTime> typeConfig, CultureInfo culture)
{
typeConfig.ParentConfig.TypeSerializers[typeof(DateTime)] = obj => ((DateTime) obj).ToString(culture);
return typeConfig.ParentConfig;
}

public static PrintingConfig<TOwner> Using<TOwner>(this IInnerPrintingConfig<TOwner, float> typeConfig, CultureInfo culture)
{
typeConfig.ParentConfig.TypeSerializers[typeof(float)] = obj => ((float) obj).ToString(culture);
return typeConfig.ParentConfig;
}
}
}
17 changes: 17 additions & 0 deletions ObjectPrinting/Extensions/ObjectExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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<T>(this T obj, Func<PrintingConfig<T>, PrintingConfig<T>> config)
{
return config(ObjectPrinter.For<T>()).PrintToString(obj);
}
}
}
12 changes: 12 additions & 0 deletions ObjectPrinting/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace ObjectPrinting.Extensions
{
public static class StringExtensions
{
public static string Truncate(this string text, int maxLength, string truncationSuffix = "")
{
return text.Length > maxLength
? text[..maxLength] + truncationSuffix
: text;
}
}
}
18 changes: 18 additions & 0 deletions ObjectPrinting/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ObjectPrinting.PropertyOrField;

namespace ObjectPrinting.Extensions
{
public static class TypeExtensions
{
public static IEnumerable<IPropertyOrField> GetFieldsAndProperties(this Type type, BindingFlags bindingAttr)
{
return type.GetFields(bindingAttr)
.Select(x => new PropertyOrField.PropertyOrField(x))
.Concat(type.GetProperties(bindingAttr).Select(x => new PropertyOrField.PropertyOrField(x)));
}
}
}
7 changes: 7 additions & 0 deletions ObjectPrinting/InnerPrintingConfig/IInnerPrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ObjectPrinting.InnerPrintingConfig
{
public interface IInnerPrintingConfig<TOwner, TTypeOrPropType>
{
PrintingConfig<TOwner> ParentConfig { get; }
}
}
35 changes: 35 additions & 0 deletions ObjectPrinting/InnerPrintingConfig/MemberPrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Reflection;
using ObjectPrinting.Extensions;

namespace ObjectPrinting.InnerPrintingConfig
{
public class MemberPrintingConfig<TOwner, TMemberType> : IInnerPrintingConfig<TOwner, TMemberType>
{
private readonly PrintingConfig<TOwner> printingConfig;
PrintingConfig<TOwner> IInnerPrintingConfig<TOwner, TMemberType>.ParentConfig => printingConfig;
private readonly MemberInfo memberInfo;

public MemberPrintingConfig(PrintingConfig<TOwner> printingConfig, MemberInfo memberInfo)
{
this.printingConfig = printingConfig;
this.memberInfo = memberInfo;
}

public PrintingConfig<TOwner> Using(Func<TMemberType, string> print)
{
printingConfig.MemberSerializers[memberInfo] = obj => print((TMemberType)obj);
return printingConfig;
}

public PrintingConfig<TOwner> TrimmedToLength(int maxLen)
{
var isSerialized = printingConfig.MemberSerializers.TryGetValue(memberInfo, out var prevSerializer);
printingConfig.MemberSerializers[memberInfo] = isSerialized
? obj => prevSerializer(obj).Truncate(maxLen)
: obj => obj.ToString().Truncate(maxLen);

return printingConfig;
}
}
}
31 changes: 31 additions & 0 deletions ObjectPrinting/InnerPrintingConfig/TypePrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using ObjectPrinting.Extensions;

namespace ObjectPrinting.InnerPrintingConfig
{
public class TypePrintingConfig<TOwner, TType> : IInnerPrintingConfig<TOwner, TType>
{
private readonly PrintingConfig<TOwner> printingConfig;
PrintingConfig<TOwner> IInnerPrintingConfig<TOwner, TType>.ParentConfig => printingConfig;

public TypePrintingConfig(PrintingConfig<TOwner> printingConfig)
{
this.printingConfig = printingConfig;
}

public PrintingConfig<TOwner> Using(Func<TType, string> print)
{
printingConfig.TypeSerializers[typeof(TType)] = obj => print((TType)obj);
return printingConfig;
}

public PrintingConfig<TOwner> TrimmedToLength(int maxLen)
{
var isSerialized = printingConfig.TypeSerializers.TryGetValue(typeof(TType), out var prevSerializer);
printingConfig.TypeSerializers[typeof(TType)] = isSerialized
? obj => prevSerializer(obj).Truncate(maxLen)
: obj => obj.ToString().Truncate(maxLen);
return printingConfig;
}
}
}
6 changes: 3 additions & 3 deletions ObjectPrinting/ObjectPrinter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace ObjectPrinting
{
public class ObjectPrinter
public static class ObjectPrinter
{
public static PrintingConfig<T> For<T>()
public static PrintingConfig<T> For<T>(int maxNestingLevel = 10)
{
return new PrintingConfig<T>();
return new PrintingConfig<T>(maxNestingLevel);
}
}
}
5 changes: 3 additions & 2 deletions ObjectPrinting/ObjectPrinting.csproj
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<LangVersion>8</LangVersion>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>9</LangVersion>
<TargetFramework>net6.0</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="NUnit" Version="3.12.0" />
</ItemGroup>
Expand Down
72 changes: 57 additions & 15 deletions ObjectPrinting/PrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -1,40 +1,82 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using ObjectPrinting.Extensions;
using ObjectPrinting.InnerPrintingConfig;

namespace ObjectPrinting
{
public class PrintingConfig<TOwner>
{
private readonly Type[] finalTypes =
{
typeof(int), typeof(double), typeof(float), typeof(string),
typeof(DateTime), typeof(TimeSpan), typeof(Guid)
};
private readonly HashSet<Type> excludedTypes = new();
private readonly HashSet<MemberInfo> excludedMembers = new();
internal readonly Dictionary<Type, Func<object, string>> TypeSerializers = new();
internal readonly Dictionary<MemberInfo, Func<object, string>> MemberSerializers = new();

Choose a reason for hiding this comment

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

Не очень хорошо, что можно получить доступ к этим полям вне класса.

private int MaxNestingLevel { get; }
public PrintingConfig(int maxNestingLevel = 10)
{
MaxNestingLevel = maxNestingLevel;
}

public TypePrintingConfig<TOwner, TType> Printing<TType>()
{
return new TypePrintingConfig<TOwner, TType>(this);
}

public MemberPrintingConfig<TOwner, TMemberType> Printing<TMemberType>(Expression<Func<TOwner, TMemberType>> memberSelector)
{
var memberInfo = ((MemberExpression) memberSelector.Body).Member;
return new MemberPrintingConfig<TOwner, TMemberType>(this, memberInfo);
}

public PrintingConfig<TOwner> Excluding<TMemberType>(Expression<Func<TOwner, TMemberType>> memberSelector)
{
var memberInfo = ((MemberExpression) memberSelector.Body).Member;
excludedMembers.Add(memberInfo);
return Excluding<TMemberType>();

Choose a reason for hiding this comment

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

Сейчас логика работает так, что если я исключаю какое-то конкретное поле, то исключаются все поля этого типа тоже. Похоже на какую-то опечатку.
Но её можно было избежать, если бы дополнить тесты и реализовать там все сценарии использования. ;)

}

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

public string PrintToString(TOwner obj)
{
return PrintToString(obj, 0);
}

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()))
var type = obj.GetType();

if (TypeSerializers.TryGetValue(obj.GetType(), out var serializer))

Choose a reason for hiding this comment

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

А почему тут не переменная type используется?

return serializer(obj) + Environment.NewLine;
if (finalTypes.Contains(type) || nestingLevel == MaxNestingLevel)
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())
var sb = new StringBuilder(type.Name + Environment.NewLine);
foreach (var propertyOrField in type.GetFieldsAndProperties(BindingFlags.Instance | BindingFlags.Public).Where(x => !excludedMembers.Contains(x.UnderlyingMember) && !excludedTypes.Contains(x.DataType)))

Choose a reason for hiding this comment

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

Давай вот это вот большое in (...) вынесем в отдельную переменную? Как-то уж слишком страшно выглядит.

Copy link
Author

Choose a reason for hiding this comment

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

Выделил в метод в новом коммите)

{
sb.Append(identation + propertyInfo.Name + " = " +
PrintToString(propertyInfo.GetValue(obj),
nestingLevel + 1));
sb.Append(identation + propertyOrField.Name + " = " +
(MemberSerializers.TryGetValue(propertyOrField.UnderlyingMember, out var propertyOrFieldSerializer)

Choose a reason for hiding this comment

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

Давай конечную сериализацию вынесем тоже в отдельную переменную? Начиная с (MemberSerializers. ...

? propertyOrFieldSerializer(propertyOrField.GetValue(obj)) + Environment.NewLine
: PrintToString(propertyOrField.GetValue(obj), nestingLevel + 1)));
}

return sb.ToString();
}
}
Expand Down
13 changes: 13 additions & 0 deletions ObjectPrinting/PropertyOrField/IPropertyOrField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Reflection;

namespace ObjectPrinting.PropertyOrField
{
public interface IPropertyOrField
{
string Name { get; }
Type DataType { get; }
MemberInfo UnderlyingMember { get; }
Func<object, object> GetValue { get; }
}
}
29 changes: 29 additions & 0 deletions ObjectPrinting/PropertyOrField/PropertyOrField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Reflection;

namespace ObjectPrinting.PropertyOrField
{
public class PropertyOrField : IPropertyOrField
{
public string Name { get; }
public Type DataType { get; }
public MemberInfo UnderlyingMember { get; }
public Func<object, object> GetValue { get; }

public PropertyOrField(PropertyInfo propertyInfo)
{
Name = propertyInfo.Name;
DataType = propertyInfo.PropertyType;
UnderlyingMember = propertyInfo;
GetValue = propertyInfo.GetValue;
}

public PropertyOrField(FieldInfo fieldInfo)
{
Name = fieldInfo.Name;
DataType = fieldInfo.FieldType;
UnderlyingMember = fieldInfo;
GetValue = fieldInfo.GetValue;
}
}
}
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