-
Notifications
You must be signed in to change notification settings - Fork 244
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
Зиновьева Милана #216
base: master
Are you sure you want to change the base?
Зиновьева Милана #216
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace ObjectPrintingHomework; | ||
|
||
public class ObjectPrinter | ||
{ | ||
public static PrintingConfig<T> For<T>() | ||
{ | ||
return new PrintingConfig<T>(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
namespace ObjectPrintingHomework; | ||
public static class ObjectPrinterExtensions | ||
{ | ||
public static string PrintToString<TOwner>(this TOwner obj) | ||
{ | ||
return ObjectPrinter.For<TOwner>().PrintToString(obj); | ||
} | ||
|
||
public static string PrintToString<TOwner>(this TOwner obj, Func<PrintingConfig<TOwner>, PrintingConfig<TOwner>> config) | ||
{ | ||
var printer = config(ObjectPrinter.For<TOwner>()); | ||
return printer.PrintToString(obj); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System.Diagnostics.Contracts; | ||
|
||
namespace ObjectPrintingHomework; | ||
|
||
public class Person | ||
{ | ||
public Guid Id { get; set; } | ||
public string Name { get; set; } | ||
public double Height { get; set; } | ||
public int Age { get; set; } | ||
public int CountEyes { get; set; } | ||
public string Surname { get; set; } | ||
public DateTime DateBirth {get; set; } | ||
public Person[] Parents { get; set; } | ||
public Person[] Friends { get; set; } | ||
public Dictionary<string, int> LimbToNumbersFingers {get; set;} | ||
public List<Person> Childs {get; set;} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
using System.Collections; | ||
using System.Diagnostics.Metrics; | ||
using System.Globalization; | ||
using System.Linq.Expressions; | ||
using System.Text; | ||
|
||
namespace ObjectPrintingHomework; | ||
public class PrintingConfig<TOwner> | ||
{ | ||
private readonly List<Type> excludedTypes = []; | ||
private readonly List<string> excludedProperties = []; | ||
private readonly Dictionary<Type, Func<object, string>> typeSerializers = []; | ||
private readonly Dictionary<string, Func<object, string>> propertySerializers = []; | ||
private readonly Dictionary<Type, CultureInfo> typeCultures = []; | ||
private readonly Dictionary<string, Tuple<int, int>> stringPropertyLengths = []; | ||
private readonly HashSet<object> processedObjects = []; | ||
|
||
public string PrintToString(TOwner obj) | ||
{ | ||
return PrintToString(obj, 0); | ||
} | ||
|
||
public PrintingConfig<TOwner> Excluding<TPropType>() | ||
{ | ||
excludedTypes.Add(typeof(TPropType)); | ||
return this; | ||
} | ||
public PrintingConfig<TOwner> Excluding<TPropType>(Expression<Func<TOwner, TPropType>> memberSelector) | ||
{ | ||
if (memberSelector.Body is not MemberExpression memberExpression) | ||
throw new ArgumentException("Needed MemberExpression"); | ||
excludedProperties.Add(memberExpression.Member.Name); | ||
return this; | ||
} | ||
|
||
public PropertyPrintingConfig<TOwner, TPropType> Printing<TPropType>() | ||
{ | ||
return new PropertyPrintingConfig<TOwner, TPropType>(this); | ||
} | ||
|
||
public PropertyPrintingConfig<TOwner, TPropType> Printing<TPropType>(Expression<Func<TOwner, TPropType>> memberSelector) | ||
{ | ||
var propertyName = ((MemberExpression)memberSelector.Body).Member.Name; | ||
return new PropertyPrintingConfig<TOwner, TPropType>(this, propertyName); | ||
} | ||
|
||
private string PrintToString(object obj, int nestingLevel) | ||
{ | ||
if (obj == null) | ||
return string.Empty; | ||
|
||
var type = obj.GetType(); | ||
|
||
if (processedObjects.Contains(obj)) | ||
return "Circular Reference"; | ||
|
||
if (excludedTypes.Contains(type)) | ||
return string.Empty; | ||
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
Sorry, something went wrong. |
||
processedObjects.Add(obj); | ||
|
||
if (obj is ICollection) | ||
return ProcessCollections(obj, nestingLevel); | ||
|
||
if (typeSerializers.TryGetValue(type, out var serializer)) | ||
return serializer(obj); | ||
|
||
if (typeCultures.TryGetValue(type, out var culture) && obj is IFormattable formattable) | ||
return formattable.ToString(null, culture); | ||
|
||
if (type.IsSerializable && type.Namespace.StartsWith("System")) | ||
return obj.ToString(); | ||
|
||
var indentation = new string('\t', nestingLevel + 1); | ||
var sb = new StringBuilder(); | ||
sb.AppendLine(type.Name); | ||
|
||
foreach (var propertyInfo in type.GetProperties()) | ||
{ | ||
var propertyType = propertyInfo.PropertyType; | ||
var propertyName = propertyInfo.Name; | ||
var propertyValue = propertyInfo.GetValue(obj); | ||
|
||
if (propertySerializers.TryGetValue(propertyName, out var propertySerializer)) | ||
{ | ||
sb.AppendLine(propertySerializer(propertyValue)); | ||
continue; | ||
} | ||
|
||
if (propertyValue is string stringValue && stringPropertyLengths.TryGetValue(propertyName, out var length)) | ||
propertyValue = stringValue.Substring(Math.Min(length.Item1, stringValue.Length))[..Math.Min(length.Item2, stringValue.Length)]; | ||
|
||
if (excludedTypes.Contains(propertyType) || excludedProperties.Contains(propertyName)) | ||
continue; | ||
|
||
sb.Append(indentation + propertyName + " = "); | ||
sb.AppendLine(PrintToString(propertyValue, nestingLevel + 1)); | ||
} | ||
|
||
return sb.ToString(); | ||
} | ||
|
||
public void AddTypeSerializer<TPropType>(Func<TPropType, string> serializer) | ||
{ | ||
typeSerializers[typeof(TPropType)] = obj => serializer((TPropType)obj); | ||
} | ||
|
||
public void AddPropertySerializer(string propertyName, Func<object, string> serializer) | ||
{ | ||
propertySerializers[propertyName] = serializer; | ||
} | ||
|
||
public void SetCulture<TPropType>(CultureInfo culture) | ||
{ | ||
typeCultures[typeof(TPropType)] = culture; | ||
} | ||
|
||
public void SetStringPropertyLength(string propertyName, int startIndex, int maxLength) | ||
{ | ||
stringPropertyLengths[propertyName] = new Tuple<int, int>(startIndex, maxLength); | ||
} | ||
|
||
private string ProcessCollections(object obj, int nestingLevel){ | ||
if (obj is IDictionary dictionary) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ещё докопался: тут будет круче воткнуть IReadonlyDictionary, тк у него больше реализаций, но это будет всё тот же словарь, и если клиенту сковородка на голову упадёт, и он решит реализовать свой словарь, то он стопроц будет реализовывать IReadonlyDictionary (если сковородкой не так сильно огрело) |
||
return ExecuteDictionary(dictionary, nestingLevel); | ||
else{ | ||
var collection = (IEnumerable)obj; | ||
return ExecuteIEnumerable(collection, nestingLevel); | ||
} | ||
} | ||
|
||
private string ExecuteDictionary(IDictionary dictionary, int nestingLevel) | ||
{ | ||
var sb = new StringBuilder(); | ||
foreach(var key in dictionary.Keys){ | ||
sb.Append("{" + PrintToString(key, nestingLevel + 1) + " = "); | ||
sb.Append(PrintToString(dictionary[key], nestingLevel + 1) + "}; "); | ||
} | ||
return sb.ToString(); | ||
} | ||
|
||
private string ExecuteIEnumerable(IEnumerable collection, int nestingLevel) | ||
{ | ||
var sb = new StringBuilder(); | ||
sb.Append('\n'); | ||
foreach(var value in collection){ | ||
sb.Append('\t', nestingLevel + 1); | ||
sb.Append(PrintToString(value, nestingLevel + 1)); | ||
} | ||
return sb.ToString(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using System.Globalization; | ||
|
||
namespace ObjectPrintingHomework; | ||
|
||
public class PropertyPrintingConfig<TOwner, TPropType> | ||
{ | ||
private readonly PrintingConfig<TOwner> parentConfig; | ||
private readonly string propertyName; | ||
|
||
public PropertyPrintingConfig(PrintingConfig<TOwner> parentConfig, string propertyName = null) | ||
{ | ||
this.parentConfig = parentConfig; | ||
this.propertyName = propertyName; | ||
} | ||
|
||
public PrintingConfig<TOwner> Using(Func<TPropType, string> serializer) | ||
{ | ||
if (propertyName == null) | ||
parentConfig.AddTypeSerializer(serializer); | ||
else | ||
parentConfig.AddPropertySerializer(propertyName, obj => serializer((TPropType)obj)); | ||
|
||
return parentConfig; | ||
} | ||
|
||
public PrintingConfig<TOwner> Using(Func<TPropType, CultureInfo> culture) | ||
{ | ||
parentConfig.SetCulture<TPropType>(culture(default!)); | ||
return parentConfig; | ||
} | ||
|
||
public PrintingConfig<TOwner> TrimmedToLength(int startIndex, int maxLength) | ||
{ | ||
if (typeof(TPropType) != typeof(string)) | ||
throw new InvalidOperationException("Trimming is only supported for string properties"); | ||
|
||
if (propertyName == null) | ||
throw new InvalidOperationException("Property name must be specified for trimming"); | ||
|
||
parentConfig.SetStringPropertyLength(propertyName, startIndex, maxLength); | ||
return parentConfig; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using System.Globalization; | ||
using ObjectPrintingHomework; | ||
|
||
namespace TestsObjectPrinting; | ||
|
||
[TestFixture] | ||
public class ObjectPrinterAcceptanceTests | ||
{ | ||
[Test] | ||
public void Demo() | ||
{ | ||
var person = new Person { Name = "Alex", Age = 19 }; | ||
|
||
var printer = ObjectPrinter.For<Person>() | ||
//1. Исключить из сериализации свойства определенного типа | ||
.Excluding<int>() | ||
//2. Указать альтернативный способ сериализации для определенного типа | ||
.Printing<int>().Using(i => i.ToString("X")) | ||
//3. Для числовых типов указать культуру | ||
.Printing<double>().Using(i => new CultureInfo("ar-EG")) | ||
//4. Настроить сериализацию конкретного свойства | ||
.Printing<double>(p => p.Height).Using(i => new CultureInfo("ar-EG")) | ||
//5. Настроить обрезание строковых свойств (метод должен быть виден только для строковых свойств) | ||
.Printing(p => p.Name).TrimmedToLength(0, 10) | ||
//6. Исключить из сериализации конкретного свойства | ||
.Excluding(p => p.Age); | ||
|
||
string s1 = printer.PrintToString(person); | ||
Console.WriteLine(s1); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
|
||
<IsPackable>false</IsPackable> | ||
<IsTestProject>true</IsTestProject> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="coverlet.collector" Version="6.0.0" /> | ||
<PackageReference Include="FluentAssertions" Version="6.12.0" /> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> | ||
<PackageReference Include="NUnit" Version="3.14.0" /> | ||
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" /> | ||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="../ObjectPrintingHomework/ObjectPrintingHomework.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Using Include="NUnit.Framework" /> | ||
</ItemGroup> | ||
|
||
</Project> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
докопался: дети по-английски - children, а словарь конечностей к числу пальцев - LimbToFingersCount