Skip to content
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
13 changes: 13 additions & 0 deletions ObjectPrinting/ObjectExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace ObjectPrinting;

public static class ObjectExtensions
{
public static string PrintToString<T>(this T obj, Func<PrintingConfig<T>, PrintingConfig<T>> config)
{
var printingConfig = ObjectPrinter.For<T>();
printingConfig = config(printingConfig);
return printingConfig.PrintToString(obj);
}
}
6 changes: 6 additions & 0 deletions ObjectPrinting/ObjectPrinter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
using System;
using System.Collections.Generic;

namespace ObjectPrinting
{
public class ObjectPrinter
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Выглядит как статический класс

{

public static PrintingConfig<T> For<T>()
{
return new PrintingConfig<T>();
}


}
}
4 changes: 3 additions & 1 deletion ObjectPrinting/ObjectPrinting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
</ItemGroup>
</Project>

</Project>
109 changes: 101 additions & 8 deletions ObjectPrinting/PrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,134 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using ObjectPrinting;

namespace ObjectPrinting
{
public class PrintingConfig<TOwner>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: Обычно делаю все классы по умолчанию sealed. Это такая холиварная нанооптимизация + заставляет лишний раз подумать, прежде чем расширять какой-либо класс

{
private HashSet<Type> excludingTypes = new();
private HashSet<string> excludingProperties = new();
private readonly Dictionary<Type, Func<object, string>> typeSerializers = new();
private readonly Dictionary<string, Func<object, string>> propertiesSerializers = new();


public PropertyPrintingConfig<TOwner, TProp> ConfigureProperty<TProp>(Expression<Func<TOwner, TProp>> propertySelector)
{
var propertyName = ((MemberExpression)propertySelector.Body).Member.Name;
return new PropertyPrintingConfig<TOwner, TProp>(this, propertyName);
}

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

public PrintingConfig<TOwner> Exclude<TProp>(Expression<Func<TOwner, TProp>> propertySelector)
{
var propertyName = ((MemberExpression)propertySelector.Body).Member.Name;
excludingProperties.Add(propertyName);
return this;
}

public TypePrintingConfig<TOwner, TPropType> ConfigureType<TPropType>()
{
return new TypePrintingConfig<TOwner, TPropType>(this);
}

internal void AddPropertySerializer<TProp>(string propertyName, Func<TProp, string> serializer)
{
propertiesSerializers[propertyName] = obj =>
{
var value = (TProp)obj;



return serializer(value);
};
}

internal void AddTypeSerializer<TPropType>(Func<TPropType, string> serializer)
{
typeSerializers[typeof(TPropType)] = obj => serializer((TPropType)obj);
}

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

if (typeSerializers.TryGetValue(objectType, out var serializer))
{
return serializer(obj) + Environment.NewLine;
}


var finalTypes = new[]
{
typeof(int), typeof(double), typeof(float), typeof(string),
typeof(DateTime), typeof(TimeSpan)
};
if (finalTypes.Contains(obj.GetType()))
if (finalTypes.Contains(objectType))
{
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.AppendLine(objectType.Name);
foreach (var propertyInfo in objectType.GetProperties())
{
sb.Append(identation + propertyInfo.Name + " = " +
PrintToString(propertyInfo.GetValue(obj),
nestingLevel + 1));
var propertyName = propertyInfo.Name;
var propertyType = propertyInfo.PropertyType;

if (excludingProperties.Contains(propertyName) || excludingTypes.Contains(propertyType))
continue;

var propertyValue = propertyInfo.GetValue(obj);
string serializedValue = GetSerializedValue(propertyValue, propertyName, nestingLevel);

sb.Append(identation + propertyName + " = " + serializedValue);
}

return sb.ToString();
}


private string GetSerializedValue(object value, string propertyName, int nestingLevel)
{

if (propertiesSerializers.TryGetValue(propertyName, out var propertySerializer))
{
return propertySerializer(value) + Environment.NewLine;
}

if (value != null && typeSerializers.TryGetValue(value.GetType(), out var typeSerializer))
{
return typeSerializer(value) + Environment.NewLine;
}


return PrintToString(value, nestingLevel + 1);
}
}





}
22 changes: 22 additions & 0 deletions ObjectPrinting/PropertyPrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;

namespace ObjectPrinting;

public class PropertyPrintingConfig<TOwner, TProp>
{
private readonly PrintingConfig<TOwner> parentConfig;
private readonly string propertyName;

public PropertyPrintingConfig(PrintingConfig<TOwner> parentConfig, string propertyName)
{
this.parentConfig = parentConfig;
this.propertyName = propertyName;
}

public PrintingConfig<TOwner> Using(Func<TProp, string> serializer)
{
parentConfig.AddPropertySerializer(propertyName, serializer);
return parentConfig;
}

}
29 changes: 29 additions & 0 deletions ObjectPrinting/PropertyPrintingConfigExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;

namespace ObjectPrinting;

public static class PropertyPrintingConfigExtensions
{
public static PrintingConfig<TOwner> TrimTo<TOwner>(this PropertyPrintingConfig<TOwner, string> config, int maxLength)
{
Func<string, string> serializer = str =>
{
if (str == null) { return "null";}

string result;
if (str.Length > maxLength)
{
result = str.Substring(0, maxLength);
}
else
{
result = str;
}

return result;
Comment on lines +13 to +23
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: можно заменить result на return и/или схлопнуть в тернарник


};

return config.Using(serializer);
}
}
Loading