Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c742582
deleted solved directory and basic tests structure
nbdevncrs Nov 18, 2025
297db5e
added tests for ObjectPrinter in new project for TDD
nbdevncrs Nov 18, 2025
09b3d1d
added PrintingSettings.cs to ObjectPrinter that will include informat…
nbdevncrs Nov 18, 2025
c86c148
added configs that take information from method calls and put it in p…
nbdevncrs Nov 18, 2025
7f0c50e
added trim extension method to configs so only call with string type …
nbdevncrs Nov 18, 2025
0c568c7
added ObjectPrinter extensions
nbdevncrs Nov 18, 2025
b8d005c
added settings appliers for each possible serialization method
nbdevncrs Nov 18, 2025
042fc39
added printing context creation that serialize all properties and typ…
nbdevncrs Nov 18, 2025
35e6930
added formatter that takes the tree with properties and creates prope…
nbdevncrs Nov 18, 2025
9cd1c4e
little configs refactor
nbdevncrs Nov 19, 2025
5b436bc
got rid of DynamicInvoke with delegates
nbdevncrs Nov 19, 2025
aef7098
deleted last PrintToString implementation
nbdevncrs Nov 20, 2025
beaa56e
added new ValueContext for PrintToString implementation
nbdevncrs Nov 20, 2025
83d7e76
added new settings appliers without recursive applying
nbdevncrs Nov 20, 2025
56c3baf
added appliers results and runner for correct applying all of the set…
nbdevncrs Nov 20, 2025
241850b
added strategies to handle different types of objects
nbdevncrs Nov 20, 2025
6b387fe
added new PrintingEngine.cs that works with appliers and strategies l…
nbdevncrs Nov 20, 2025
1a951d2
added new tests, edited expected files for new more pretty enumerable…
nbdevncrs Nov 20, 2025
e478c2d
added trim for string type, handled it in trim applier with less prio…
nbdevncrs Nov 22, 2025
80f668b
restricted use method with culture for non-formattable types
nbdevncrs Nov 22, 2025
045fe7f
renamed settings appliers
nbdevncrs Nov 22, 2025
1685801
deleted IFormattable check after restricting culture use for non-nume…
nbdevncrs Nov 22, 2025
1b87d86
merged serializer appliers for type and properties into one
nbdevncrs Nov 22, 2025
0c8bb3b
added span for string trimming
nbdevncrs Nov 22, 2025
3c88501
deleted local context, editing only context.Value with appliers
nbdevncrs Nov 22, 2025
306a139
added Enviroment.NewLine instead of \r\n and \n to split
nbdevncrs Nov 22, 2025
fab41c7
edited enumerable default serializing (also edited tests so new defau…
nbdevncrs Nov 22, 2025
db4f53a
edited bad switch to if statement
nbdevncrs Nov 22, 2025
e60e250
move several primitive types check into helper
nbdevncrs Nov 22, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using ObjectPrinting.Configs.Interfaces;

namespace ObjectPrinting.Configs.Extensions;

public static class PropertyPrintingConfigExtensions
{
public static PrintingConfig<TOwner> Trim<TOwner>(
this PropertyPrintingConfig<TOwner, string> config,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Почему нельзя обрезать все строки, а только конкретные пропы?

int maxLen)
{
ArgumentOutOfRangeException.ThrowIfNegative(maxLen);

var parent = ((IChildPrintingConfig<TOwner, string>)config).ParentConfig;

var path = config.PropertyPath;

parent.Settings.StringTrimLengths[path] = maxLen;

return parent;
}
}
34 changes: 34 additions & 0 deletions ObjectPrinting/Configs/Extensions/TypePrintingConfigExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Numerics;
using ObjectPrinting.Configs.Interfaces;

namespace ObjectPrinting.Configs.Extensions;

public static class TypePrintingConfigExtensions
{
public static PrintingConfig<TOwner> Trim<TOwner>(
this TypePrintingConfig<TOwner, string> config,
int maxLen)
{
ArgumentOutOfRangeException.ThrowIfNegative(maxLen);

var parent = ((IChildPrintingConfig<TOwner, string>)config).ParentConfig;

parent.Settings.GlobalStringTrimLength = maxLen;

return parent;
}

public static PrintingConfig<TOwner> Use<TOwner, TPropType>(
this TypePrintingConfig<TOwner, TPropType> config,
IFormatProvider provider) where TPropType : IFormattable
{
ArgumentNullException.ThrowIfNull(provider);

var parent = ((IChildPrintingConfig<TOwner, TPropType>)config).ParentConfig;

parent.Settings.TypeCultures[typeof(TPropType)] = provider;

return parent;
}
}
6 changes: 6 additions & 0 deletions ObjectPrinting/Configs/Interfaces/IChildPrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace ObjectPrinting.Configs.Interfaces;

public interface IChildPrintingConfig<TOwner, TPropType>
{
PrintingConfig<TOwner> ParentConfig { get; }
}
26 changes: 26 additions & 0 deletions ObjectPrinting/Configs/PrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Linq.Expressions;
using ObjectPrinting.PrintingHandlers;

namespace ObjectPrinting.Configs;

public class PrintingConfig<TOwner>(PrintingSettings settings)
{
public readonly PrintingSettings Settings = settings;

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

public PropertyPrintingConfig<TOwner, TPropType> For<TPropType>(Expression<Func<TOwner, TPropType>> selector)
{
return new PropertyPrintingConfig<TOwner, TPropType>(this, selector);
}

public string PrintToString(TOwner obj)
{
var engine = new PrintingEngine(Settings);
return engine.Print(obj);
}
}
50 changes: 50 additions & 0 deletions ObjectPrinting/Configs/PropertyPrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Linq.Expressions;
using ObjectPrinting.Configs.Interfaces;

namespace ObjectPrinting.Configs;

public class PropertyPrintingConfig<TOwner, TPropType> : IChildPrintingConfig<TOwner, TPropType>
{
private readonly PrintingConfig<TOwner> printingConfig;
public readonly string PropertyPath;

PrintingConfig<TOwner> IChildPrintingConfig<TOwner, TPropType>.ParentConfig => printingConfig;

internal PropertyPrintingConfig(PrintingConfig<TOwner> parentConfig, Expression<Func<TOwner, TPropType>> selector)
{
printingConfig = parentConfig ?? throw new ArgumentNullException(nameof(parentConfig));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Прям везде проверять на null можно, но не обязательно. Я бы склонялся к тому, что всё должны описывать сигнатуры. Если в сигнатуре поле !nulalble а кто-то прокидывает туда его - это на его совести(и ему же огребать в большинстве случаев)

PropertyPath = BuildMemberPath(selector);
}

public PrintingConfig<TOwner> Use(Func<TPropType, string> serializer)
{
ArgumentNullException.ThrowIfNull(serializer);

printingConfig.Settings.PropertySerializers[PropertyPath] = obj => serializer((TPropType)obj!);
return printingConfig;
}

public PrintingConfig<TOwner> Exclude()
{
printingConfig.Settings.ExcludedProperties.Add(PropertyPath);
return printingConfig;
}

private static string BuildMemberPath(Expression<Func<TOwner, TPropType>> selector)
{
ArgumentNullException.ThrowIfNull(selector);

var expression = selector.Body;
var parts = new System.Collections.Generic.List<string>();
while (expression is MemberExpression m)
{
parts.Add(m.Member.Name);
expression = m.Expression;
}

parts.Reverse();
var ownerName = typeof(TOwner).Name;
return ownerName + "." + string.Join('.', parts);
}
}
29 changes: 29 additions & 0 deletions ObjectPrinting/Configs/TypePrintingConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using ObjectPrinting.Configs.Interfaces;

namespace ObjectPrinting.Configs;

public class TypePrintingConfig<TOwner, TPropType> : IChildPrintingConfig<TOwner, TPropType>
{
private readonly PrintingConfig<TOwner> printingConfig;

PrintingConfig<TOwner> IChildPrintingConfig<TOwner, TPropType>.ParentConfig => printingConfig;

internal TypePrintingConfig(PrintingConfig<TOwner> parentConfig)
{
printingConfig = parentConfig ?? throw new ArgumentNullException(nameof(parentConfig));
}

public PrintingConfig<TOwner> Use(Func<TPropType, string> serializer)
{
ArgumentNullException.ThrowIfNull(serializer);
printingConfig.Settings.TypeSerializers[typeof(TPropType)] = obj => serializer((TPropType)obj!);
return printingConfig;
}

public PrintingConfig<TOwner> Exclude()
{
printingConfig.Settings.ExcludedTypes.Add(typeof(TPropType));
return printingConfig;
}
}
13 changes: 7 additions & 6 deletions ObjectPrinting/ObjectPrinter.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
namespace ObjectPrinting
using ObjectPrinting.Configs;

namespace ObjectPrinting;

public class ObjectPrinter
{
public class ObjectPrinter
public static PrintingConfig<T> InClass<T>()
{
public static PrintingConfig<T> For<T>()
{
return new PrintingConfig<T>();
}
return new PrintingConfig<T>(new PrintingSettings());
}
}
19 changes: 19 additions & 0 deletions ObjectPrinting/ObjectPrinterExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using ObjectPrinting.Configs;

namespace ObjectPrinting;

public static class ObjectPrinterExtensions
{
public static string PrintToString<T>(this T obj)
{
return ObjectPrinter.InClass<T>().PrintToString(obj);
}

public static string PrintToString<T>(this T obj, Func<PrintingConfig<T>, PrintingConfig<T>> config)
{
ArgumentNullException.ThrowIfNull(config);
var printer = config(ObjectPrinter.InClass<T>());
return printer.PrintToString(obj);
}
}
4 changes: 1 addition & 3 deletions ObjectPrinting/ObjectPrinting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
</ItemGroup>
</Project>
41 changes: 0 additions & 41 deletions ObjectPrinting/PrintingConfig.cs

This file was deleted.

27 changes: 27 additions & 0 deletions ObjectPrinting/PrintingHandlers/ApplyingSettings/ApplierResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace ObjectPrinting.PrintingHandlers.ApplyingSettings;

public readonly struct ApplierResult
{
public bool Applied { get; }
public bool Exclude { get; }
public string? Serialized { get; }
public object? NewValue { get; }

private ApplierResult(bool applied, bool exclude, string? serialized, object? newValue)
{
Applied = applied;
Exclude = exclude;
Serialized = serialized;
NewValue = newValue;
}

public static ApplierResult NotApplied => new(false, false, null, null);

public static ApplierResult Excluded() => new(true, true, null, null);

public static ApplierResult SerializedValue(string value) =>
new(true, false, value, null);

public static ApplierResult Modified(object? newValue) =>
new(true, false, null, newValue);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using ObjectPrinting.PrintingHandlers.ApplyingSettings.Interfaces;

namespace ObjectPrinting.PrintingHandlers.ApplyingSettings.Appliers;

internal class CultureSettingsApplier : ISettingsApplier
{
public ApplierResult Apply(ValueContext context)
{
if (context.Type == null ||
!context.Settings.TypeCultures.TryGetValue(context.Type, out var culture))
return ApplierResult.NotApplied;

var str = ((IFormattable)context.Value).ToString(null, culture);
return ApplierResult.SerializedValue(str);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using ObjectPrinting.PrintingHandlers.ApplyingSettings.Interfaces;

namespace ObjectPrinting.PrintingHandlers.ApplyingSettings.Appliers;

internal class ExcludeSettingsApplier : ISettingsApplier
{
public ApplierResult Apply(ValueContext context)
{
if (context.Settings.ExcludedProperties.Contains(context.Path) ||
(context.Type != null && context.Settings.ExcludedTypes.Contains(context.Type)))
return ApplierResult.Excluded();

return ApplierResult.NotApplied;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using ObjectPrinting.PrintingHandlers.ApplyingSettings.Interfaces;

namespace ObjectPrinting.PrintingHandlers.ApplyingSettings.Appliers;

internal class SerializerSettingsApplier : ISettingsApplier
{
public ApplierResult Apply(ValueContext context)
{
if (context.Settings.PropertySerializers.TryGetValue(context.Path, out var propertySerializer))
return ApplierResult.SerializedValue(propertySerializer(context.Value));

if (context.Type != null &&
context.Settings.TypeSerializers.TryGetValue(context.Type, out var typeSerializer))
return ApplierResult.SerializedValue(typeSerializer(context.Value));

return ApplierResult.NotApplied;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using ObjectPrinting.PrintingHandlers.ApplyingSettings.Interfaces;

namespace ObjectPrinting.PrintingHandlers.ApplyingSettings.Appliers;

internal class TrimStringSettingsApplier : ISettingsApplier
{
public ApplierResult Apply(ValueContext context)
{
if (context.Type != typeof(string) || context.Value is not string s)
return ApplierResult.NotApplied;

var settings = context.Settings;

if (settings.StringTrimLengths.TryGetValue(context.Path, out var propertyMax))
{
return ApplierResult.Modified(s.Length <= propertyMax ? s : s.AsSpan(0, propertyMax).ToString());
}

if (settings.GlobalStringTrimLength <= 0) return ApplierResult.NotApplied;

var max = settings.GlobalStringTrimLength;
return ApplierResult.Modified(s.Length <= max ? s : s.AsSpan(0, max).ToString());
}
}
Loading