-
Notifications
You must be signed in to change notification settings - Fork 245
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
Черных Илья #214
Open
Ilya4rh
wants to merge
27
commits into
kontur-courses:master
Choose a base branch
from
Ilya4rh:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Черных Илья #214
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
2633ab8
Добавил файл настроек
Ilya4rh 8bc8d66
Изменение namespace
Ilya4rh 88a3a90
Добавил метод исключения типа
Ilya4rh d8b0236
Добавление альтернативного способа сериализации для типа
Ilya4rh 889888f
Добавил возможность указать культуру
Ilya4rh e20d432
Добавил настройку сериализации для свойств
Ilya4rh 56d4a0f
Добавил возможность обрезания строк
Ilya4rh f3fb3ec
Добавил исключение свойства
Ilya4rh d838593
Добавил сереализацию
Ilya4rh a122f24
Добавил новые методы
Ilya4rh 3473d00
Добавил новый тип
Ilya4rh bfa1ca5
Добавил тесты
Ilya4rh 3106b0d
Небольшое изменение в Person
Ilya4rh 6f58e53
Добавил тест на исключение свойства
Ilya4rh 4bdf302
Переделал тесты с использованием Verify, добавил снепшоты
Ilya4rh 7700886
Изменение в тестах
Ilya4rh c03e015
Удалил папку Solved
Ilya4rh e0d69a1
Добавил интерфейс и классы
Ilya4rh bebeeac
Изменил имеющиеся классы под новую логику
Ilya4rh d04152a
Рефакторинг PrintingConfig
Ilya4rh 141a69e
Удалил интерфейс
Ilya4rh 70dbf25
Изменил тест
Ilya4rh eed9c25
Перенес метод
Ilya4rh 5e9c655
Изменил модификатор доступа для PropertyName
Ilya4rh 4760a11
Добавил возможность указания культуры для определенного свойства
Ilya4rh 43efbd4
Изменил finalTypes, добавил проверку на примитивные типы
Ilya4rh 6cc1432
Добавил bool свойство в Person
Ilya4rh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
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); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
ObjectPrinting/Extensions/PropertyPrintingConfigExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
|
||
namespace ObjectPrinting.Extensions; | ||
|
||
public static class PropertyPrintingConfigExtensions | ||
{ | ||
public static PrintingConfig<TOwner> TrimmedToLength<TOwner>( | ||
this PropertyPrintingConfig<TOwner, string> propConfig, | ||
int maxLen) | ||
{ | ||
if (string.IsNullOrEmpty(propConfig.PropertyName)) | ||
throw new ArgumentException("The name of the property is not specified."); | ||
|
||
propConfig.ParentConfig.AddLengthProperty(propConfig.PropertyName, maxLen); | ||
|
||
return propConfig.ParentConfig; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,9 @@ | ||
namespace ObjectPrinting | ||
namespace ObjectPrinting; | ||
|
||
public static class ObjectPrinter | ||
{ | ||
public class ObjectPrinter | ||
public static PrintingConfig<T> For<T>() | ||
{ | ||
public static PrintingConfig<T> For<T>() | ||
{ | ||
return new PrintingConfig<T>(); | ||
} | ||
return new PrintingConfig<T>(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,215 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using System.Text; | ||
|
||
namespace ObjectPrinting | ||
namespace ObjectPrinting; | ||
|
||
public class PrintingConfig<TOwner> | ||
{ | ||
public class PrintingConfig<TOwner> | ||
private readonly HashSet<Type> finalTypes = | ||
[ | ||
typeof(string), typeof(DateTime), typeof(TimeSpan), typeof(Guid) | ||
]; | ||
private readonly HashSet<Type> excludedTypes = []; | ||
private readonly Dictionary<Type, Func<object, string>> typeSerializationMethods = []; | ||
private readonly Dictionary<Type, IFormatProvider> typeCultures = []; | ||
private readonly Dictionary<string, IFormatProvider> propertyCultures = []; | ||
private readonly Dictionary<string, Func<object, string>> propertySerializationMethods = []; | ||
private readonly HashSet<string> excludedProperties = []; | ||
private readonly HashSet<object> processedObjects = []; | ||
private readonly Dictionary<string, int> propertyLengths = new(); | ||
|
||
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 = GetPropertyName(memberSelector); | ||
|
||
return new PropertyPrintingConfig<TOwner, TPropType>(this, propertyName); | ||
} | ||
|
||
public string PrintToString(TOwner obj) | ||
{ | ||
return PrintToString(obj, 0); | ||
} | ||
|
||
private string PrintToString(object? obj, int nestingLevel) | ||
{ | ||
public string PrintToString(TOwner obj) | ||
if (obj == null) | ||
{ | ||
return PrintToString(obj, 0); | ||
return "null" + Environment.NewLine; | ||
} | ||
|
||
private string PrintToString(object obj, int nestingLevel) | ||
if (processedObjects.Contains(obj)) | ||
{ | ||
//TODO apply configurations | ||
if (obj == null) | ||
return "null" + Environment.NewLine; | ||
return "Circular Reference" + Environment.NewLine; | ||
} | ||
|
||
var finalTypes = new[] | ||
{ | ||
typeof(int), typeof(double), typeof(float), typeof(string), | ||
typeof(DateTime), typeof(TimeSpan) | ||
}; | ||
if (finalTypes.Contains(obj.GetType())) | ||
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()) | ||
if (TrySerializeFinalType(obj, out var serializedFinalType)) | ||
{ | ||
return serializedFinalType!; | ||
} | ||
|
||
if (TrySerializeCollection(obj, nestingLevel, out var serializedCollection)) | ||
{ | ||
return serializedCollection!; | ||
} | ||
|
||
return SerializeComplexType(obj, nestingLevel); | ||
} | ||
|
||
public PrintingConfig<TOwner> Excluding<TPropType>() | ||
{ | ||
excludedTypes.Add(typeof(TPropType)); | ||
return this; | ||
} | ||
|
||
public PrintingConfig<TOwner> Excluding<TPropType>(Expression<Func<TOwner, TPropType>> memberSelector) | ||
{ | ||
var propertyName = GetPropertyName(memberSelector); | ||
excludedProperties.Add(propertyName); | ||
return this; | ||
} | ||
|
||
public void SpecifyTheCulture<TType>(CultureInfo culture) | ||
{ | ||
typeCultures[typeof(TType)] = culture; | ||
} | ||
|
||
public void SpecifyTheCulture(CultureInfo culture, string propertyName) | ||
{ | ||
propertyCultures[propertyName] = culture; | ||
} | ||
|
||
public void AddSerializationMethod<TType>(Func<TType, string> serializationMethod) | ||
{ | ||
typeSerializationMethods[typeof(TType)] = obj => serializationMethod((TType)obj); | ||
} | ||
|
||
public void AddSerializationMethod<TType>(Func<TType, string> serializationMethod, string propertyName) | ||
{ | ||
propertySerializationMethods[propertyName] = obj => serializationMethod((TType)obj); | ||
} | ||
|
||
public void AddLengthProperty(string propertyName, int trimLength) | ||
{ | ||
propertyLengths[propertyName] = trimLength; | ||
} | ||
|
||
private bool TrySerializeFinalType(object obj, out string? serializedFinalType) | ||
{ | ||
var type = obj.GetType(); | ||
|
||
if (!finalTypes.Contains(type) && !type.IsPrimitive) | ||
{ | ||
serializedFinalType = null; | ||
return false; | ||
} | ||
|
||
serializedFinalType = obj switch | ||
{ | ||
IFormattable format when typeCultures.TryGetValue(type, out var formatProvider) => | ||
format.ToString(null, formatProvider), | ||
IFormattable format => | ||
format.ToString(null, CultureInfo.InvariantCulture), | ||
string str => str, | ||
_ => Convert.ToString(obj) | ||
}; | ||
|
||
serializedFinalType += Environment.NewLine; | ||
|
||
return true; | ||
} | ||
|
||
private bool TrySerializeCollection(object obj, int nestingLevel, out string? serializedCollection) | ||
{ | ||
if (obj is not IEnumerable collection) | ||
{ | ||
serializedCollection = null; | ||
return false; | ||
} | ||
|
||
var collectionOnString = new StringBuilder(); | ||
var indentation = new string('\t', nestingLevel + 1); | ||
var type = obj.GetType(); | ||
|
||
collectionOnString.AppendLine($"{type.Name}:"); | ||
|
||
foreach (var item in collection) | ||
{ | ||
collectionOnString.Append(indentation + PrintToString(item, nestingLevel + 1)); | ||
} | ||
|
||
serializedCollection = collectionOnString.ToString(); | ||
return true; | ||
} | ||
|
||
private string SerializeComplexType(object obj, int nestingLevel) | ||
{ | ||
processedObjects.Add(obj); | ||
var serializedString = new StringBuilder(); | ||
var indentation = new string('\t', nestingLevel + 1); | ||
var type = obj.GetType(); | ||
|
||
serializedString.AppendLine(type.Name); | ||
|
||
foreach (var property in type.GetProperties()) | ||
{ | ||
if (excludedTypes.Contains(property.PropertyType) || excludedProperties.Contains(property.Name)) | ||
{ | ||
sb.Append(identation + propertyInfo.Name + " = " + | ||
PrintToString(propertyInfo.GetValue(obj), | ||
nestingLevel + 1)); | ||
continue; | ||
} | ||
return sb.ToString(); | ||
|
||
var serializedProperty = SerializeProperty(property, obj, nestingLevel + 1); | ||
serializedString.Append(indentation + property.Name + " = " + serializedProperty); | ||
} | ||
|
||
return serializedString.ToString(); | ||
} | ||
|
||
private string SerializeProperty(PropertyInfo property, object obj, int nestingLevel) | ||
{ | ||
var propertyValue = property.GetValue(obj); | ||
|
||
if (typeSerializationMethods.TryGetValue(property.PropertyType, out var serializationType)) | ||
{ | ||
return serializationType(propertyValue!) + Environment.NewLine; | ||
} | ||
|
||
if (propertySerializationMethods.TryGetValue(property.Name, out var serializationProperty)) | ||
{ | ||
return serializationProperty(propertyValue!) + Environment.NewLine; | ||
} | ||
|
||
if (propertyLengths.TryGetValue(property.Name, out var length)) | ||
{ | ||
var stringPropertyValue = Convert.ToString(propertyValue)!; | ||
|
||
return stringPropertyValue[..length] + Environment.NewLine; | ||
} | ||
|
||
if (propertyCultures.TryGetValue(property.Name, out var formatProvider) && propertyValue is IFormattable format) | ||
{ | ||
return format.ToString(null, formatProvider) + Environment.NewLine; | ||
} | ||
|
||
return PrintToString(propertyValue, nestingLevel); | ||
} | ||
|
||
private static string GetPropertyName<T>(Expression<Func<TOwner, T>> property) | ||
{ | ||
if (property.Body is MemberExpression member) | ||
{ | ||
return member.Member.Name; | ||
} | ||
|
||
throw new ArgumentException("Expression is not property."); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
using System; | ||
using System.Globalization; | ||
|
||
namespace ObjectPrinting; | ||
|
||
public class PropertyPrintingConfig<TOwner, TPropType> | ||
{ | ||
private readonly PrintingConfig<TOwner> printingConfig; | ||
protected internal readonly string? PropertyName; | ||
|
||
public PropertyPrintingConfig(PrintingConfig<TOwner> printingConfig, string? propertyName = null) | ||
{ | ||
this.printingConfig = printingConfig; | ||
PropertyName = propertyName; | ||
} | ||
|
||
public PrintingConfig<TOwner> Using(Func<TPropType, string> print) | ||
{ | ||
if (string.IsNullOrEmpty(PropertyName)) | ||
{ | ||
printingConfig.AddSerializationMethod(print); | ||
} | ||
else | ||
{ | ||
printingConfig.AddSerializationMethod(print, PropertyName); | ||
} | ||
|
||
return ParentConfig; | ||
} | ||
|
||
public PrintingConfig<TOwner> Using(CultureInfo culture) | ||
{ | ||
if (string.IsNullOrEmpty(PropertyName)) | ||
{ | ||
printingConfig.SpecifyTheCulture<TPropType>(culture); | ||
} | ||
else | ||
{ | ||
printingConfig.SpecifyTheCulture(culture, PropertyName); | ||
} | ||
|
||
return ParentConfig; | ||
} | ||
|
||
public PrintingConfig<TOwner> ParentConfig => printingConfig; | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
В шарпе есть ещё куча базовых типов, но как минимум стоит добавть сериализацию для long и bool