-
Notifications
You must be signed in to change notification settings - Fork 264
Шагов Владислав #247
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
Open
ShagovVladislav
wants to merge
1
commit into
kontur-courses:master
Choose a base branch
from
ShagovVladislav:hometask
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
Шагов Владислав #247
Changes from all commits
Commits
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 hidden or 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,120 @@ | ||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Text; | ||
|
|
||
| namespace ObjectPrinting | ||
| { | ||
| internal static class CollectionSerializer | ||
| { | ||
| public static bool IsCollection(Type type) | ||
| { | ||
| if (type.IsArray) | ||
| return true; | ||
|
|
||
| return typeof(IEnumerable).IsAssignableFrom(type) && | ||
| type != typeof(string); | ||
| } | ||
|
|
||
| public static bool IsDictionary(Type type) | ||
| { | ||
| if (typeof(IDictionary).IsAssignableFrom(type)) | ||
| return true; | ||
|
|
||
| return type.IsGenericType && | ||
| (type.GetGenericTypeDefinition() == typeof(Dictionary<,>) || | ||
| type.GetGenericTypeDefinition() == typeof(IDictionary<,>)); | ||
| } | ||
|
|
||
| public static string SerializeCollection(object collection, int nestingLevel, HashSet<object> visitedObjects, PrintingConfigData config) | ||
| { | ||
| var sb = new StringBuilder(); | ||
| var identation = new string('\t', nestingLevel + 1); | ||
| var collectionType = collection.GetType(); | ||
|
|
||
| sb.AppendLine("["); | ||
|
|
||
| var enumerable = (IEnumerable)collection; | ||
| var items = enumerable.Cast<object>().ToList(); | ||
| var maxItems = config.CollectionMaxItems.GetValueOrDefault(collectionType, int.MaxValue); | ||
|
|
||
| foreach (var item in items.Take(maxItems)) | ||
| { | ||
| string serializedItem; | ||
| if (config.CollectionSerializers.TryGetValue(collectionType, out var serializer)) | ||
| { | ||
| serializedItem = serializer(item); | ||
| } | ||
| else | ||
| { | ||
| var objectSerializer = new ObjectSerializer(config); | ||
| serializedItem = objectSerializer.PrintToString(item, nestingLevel + 1, visitedObjects).TrimEnd(); | ||
| } | ||
|
|
||
| sb.AppendLine(identation + serializedItem + ","); | ||
| } | ||
|
|
||
| if (items.Count > maxItems) | ||
| { | ||
| var remaining = items.Count - maxItems; | ||
| sb.AppendLine(identation + $"... and {remaining} more items"); | ||
| } | ||
| else if (items.Count == 0) | ||
| { | ||
| sb.AppendLine(identation + "empty"); | ||
| } | ||
|
|
||
| sb.AppendLine("]"); | ||
| return sb.ToString(); | ||
| } | ||
|
|
||
| public static string SerializeDictionary(object dictionary, int nestingLevel, HashSet<object> visitedObjects, PrintingConfigData config) | ||
| { | ||
| var sb = new StringBuilder(); | ||
| var identation = new string('\t', nestingLevel + 1); | ||
| var dictType = dictionary.GetType(); | ||
|
|
||
| sb.AppendLine("["); | ||
|
|
||
| try | ||
| { | ||
| var dict = (IDictionary)dictionary; | ||
| var count = 0; | ||
| var maxItems = config.CollectionMaxItems.GetValueOrDefault(dictType, int.MaxValue); | ||
| var objectSerializer = new ObjectSerializer(config); | ||
|
|
||
| foreach (DictionaryEntry entry in dict) | ||
| { | ||
| if (count >= maxItems) | ||
| { | ||
| var remaining = dict.Count - maxItems; | ||
| sb.AppendLine(identation + $"... and {remaining} more items"); | ||
| break; | ||
| } | ||
|
|
||
| var serializedKey = objectSerializer.PrintToString(entry.Key, nestingLevel + 1, visitedObjects).Trim(); | ||
| var serializedValue = objectSerializer.PrintToString(entry.Value, nestingLevel + 1, visitedObjects).Trim(); | ||
|
|
||
| serializedKey = serializedKey.Replace(Environment.NewLine, " ").Trim(); | ||
| serializedValue = serializedValue.Replace(Environment.NewLine, " ").Trim(); | ||
|
|
||
| sb.AppendLine(identation + $"{serializedKey}: {serializedValue},"); | ||
| count++; | ||
| } | ||
|
|
||
| if (count == 0) | ||
| { | ||
| sb.AppendLine(identation + "empty"); | ||
| } | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| sb.AppendLine(identation + $"Error: {ex.Message}"); | ||
| } | ||
|
|
||
| sb.AppendLine("]"); | ||
| return sb.ToString(); | ||
| } | ||
| } | ||
| } |
This file contains hidden or 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,41 @@ | ||
| using System; | ||
|
|
||
| namespace ObjectPrinting; | ||
|
|
||
| public class CollectionsConfigurator<TOwner, TCollection> | ||
| { | ||
| private readonly PrintingConfig<TOwner> _printingConfig; | ||
| private readonly PrintingConfigData _data; | ||
| private readonly Type _collectionType; | ||
|
|
||
| public CollectionsConfigurator(PrintingConfig<TOwner> printingConfig, PrintingConfigData data, Type collectionType) | ||
| { | ||
| _printingConfig = printingConfig; | ||
| _data = data; | ||
| _collectionType = collectionType; | ||
| } | ||
|
|
||
| public static implicit operator PrintingConfig<TOwner>(CollectionsConfigurator<TOwner, TCollection> configurator) | ||
| { | ||
| return configurator._printingConfig; | ||
| } | ||
|
|
||
| public CollectionsConfigurator<TOwner, TCollection> WithMaxItems(int maxItems) | ||
| { | ||
| _data.CollectionMaxItems[_collectionType] = maxItems; | ||
| return this; | ||
| } | ||
|
|
||
| public CollectionsConfigurator<TOwner, TCollection> WithItemSerialization(Func<object, string> itemSerializer) | ||
| { | ||
| _data.CollectionSerializers[_collectionType] = itemSerializer; | ||
| return this; | ||
| } | ||
|
|
||
| public string PrintToString(TOwner obj) | ||
| { | ||
| return _printingConfig.PrintToString(obj); | ||
| } | ||
|
|
||
|
|
||
| } |
This file contains hidden or 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,33 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace ObjectPrinting; | ||
|
|
||
| public static class CollectionsConfiguratorExtensions | ||
| { | ||
| public static CollectionsConfigurator<TOwner, TCollection> WithItemSerialization<TOwner, TCollection, TItem>( | ||
| this CollectionsConfigurator<TOwner, TCollection> configurator, | ||
| Func<TItem, string> itemSerializer) | ||
| { | ||
| return configurator.WithItemSerialization(obj => | ||
| { | ||
| if (obj is TItem item) | ||
| return itemSerializer(item); | ||
| return obj?.ToString() ?? "null"; | ||
| }); | ||
| } | ||
|
|
||
| public static CollectionsConfigurator<TOwner, TCollection> Trim<TOwner, TCollection>( | ||
| this CollectionsConfigurator<TOwner, TCollection> configurator, | ||
| int start, int end) | ||
| { | ||
| return configurator.WithItemSerialization(str => | ||
| { | ||
| var s = str as string; | ||
| if (s == null) return "null"; | ||
|
|
||
| var length = Math.Min(s.Length - start, end - start); | ||
| return length > 0 ? s.Substring(start, length) : string.Empty; | ||
| }); | ||
| } | ||
| } |
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -6,5 +6,6 @@ public static PrintingConfig<T> For<T>() | |
| { | ||
| return new PrintingConfig<T>(); | ||
| } | ||
|
|
||
| } | ||
| } | ||
This file contains hidden or 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; | ||
|
|
||
| public static class ObjectPrinterExtensions | ||
| { | ||
| public static string PrintToString<T>(this T obj) | ||
| { | ||
| return ObjectPrinter.For<T>().PrintToString(obj); | ||
| } | ||
|
|
||
| public static string PrintToString<T>(this T obj, Action<PrintingConfig<T>> config) | ||
| { | ||
| var printer = ObjectPrinter.For<T>(); | ||
| config(printer); | ||
| return printer.PrintToString(obj); | ||
| } | ||
| } |
This file contains hidden or 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 hidden or 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,117 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Reflection; | ||
| using System.Text; | ||
|
|
||
| namespace ObjectPrinting | ||
| { | ||
| internal class ObjectSerializer | ||
| { | ||
| private readonly PrintingConfigData _config; | ||
| private static readonly HashSet<Type> FinalTypes = new() | ||
| { | ||
| typeof(int), typeof(double), typeof(float), typeof(string), | ||
| typeof(DateTime), typeof(TimeSpan), typeof(bool), typeof(decimal), | ||
| typeof(long), typeof(short), typeof(byte), typeof(char), typeof(Guid) | ||
| }; | ||
|
|
||
| public ObjectSerializer(PrintingConfigData config) | ||
| { | ||
| _config = config; | ||
| } | ||
|
|
||
| public string Serialize(object obj) | ||
| { | ||
| return PrintToString(obj, 0, new HashSet<object>()); | ||
| } | ||
|
|
||
| public string PrintToString(object obj, int nestingLevel, HashSet<object> visitedObjects) | ||
| { | ||
| if (obj == null) | ||
| return "null" + Environment.NewLine; | ||
|
|
||
| if (!visitedObjects.Add(obj)) | ||
| return $"Cyclic reference to {obj.GetType().Name}" + Environment.NewLine; | ||
|
|
||
| try | ||
| { | ||
| var type = obj.GetType(); | ||
|
|
||
| if (FinalTypes.Contains(type)) | ||
| return ApplySerialization(obj, type) + Environment.NewLine; | ||
|
|
||
| if (CollectionSerializer.IsDictionary(type)) | ||
| return CollectionSerializer.SerializeDictionary(obj, nestingLevel, visitedObjects, _config); | ||
|
|
||
| if (CollectionSerializer.IsCollection(type)) | ||
| return CollectionSerializer.SerializeCollection(obj, nestingLevel, visitedObjects, _config); | ||
|
|
||
| return SerializeObject(obj, nestingLevel, visitedObjects); | ||
| } | ||
| finally | ||
| { | ||
| visitedObjects.Remove(obj); | ||
| } | ||
| } | ||
|
|
||
| private string SerializeObject(object obj, int nestingLevel, HashSet<object> visitedObjects) | ||
| { | ||
| 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 (_config.ExcludedTypes.Contains(propertyInfo.PropertyType) || | ||
| _config.ExcludedProperties.Contains(propertyInfo.Name)) | ||
| continue; | ||
|
|
||
| var propertyValue = propertyInfo.GetValue(obj); | ||
| var serializedValue = SerializeProperty(propertyInfo, propertyValue, nestingLevel, visitedObjects); | ||
|
|
||
| sb.Append(identation + propertyInfo.Name + " = " + serializedValue); | ||
| } | ||
|
|
||
| return sb.ToString(); | ||
| } | ||
|
|
||
| private string SerializeProperty(PropertyInfo propertyInfo, object propertyValue, int nestingLevel, HashSet<object> visitedObjects) | ||
| { | ||
| var propertyName = propertyInfo.Name; | ||
| var propertyType = propertyInfo.PropertyType; | ||
|
|
||
| if (_config.PropertySerializers.TryGetValue(propertyName, out var propertySerializer)) | ||
| return propertySerializer(propertyValue) + Environment.NewLine; | ||
|
|
||
| if (_config.PropertyCultures.TryGetValue(propertyName, out var culture) && propertyValue is IFormattable formattableProperty) | ||
| return formattableProperty.ToString(null, culture) + Environment.NewLine; | ||
|
|
||
| if (_config.TypeSerializers.TryGetValue(propertyType, out var typeSerializer)) | ||
| return typeSerializer(propertyValue) + Environment.NewLine; | ||
|
|
||
| if (_config.TypeCultures.ContainsKey(propertyType) && propertyValue is IFormattable formattable) | ||
| return formattable.ToString(null, _config.TypeCultures[propertyType]) + Environment.NewLine; | ||
|
|
||
| return PrintToString(propertyValue, nestingLevel + 1, visitedObjects); | ||
| } | ||
|
|
||
| private string ApplySerialization(object value, Type type) | ||
| { | ||
| if (value == null) | ||
| return "null"; | ||
|
|
||
| if (_config.TypeSerializers.TryGetValue(type, out var serializer)) | ||
| return serializer(value); | ||
|
|
||
| if (_config.TypeCultures.ContainsKey(type) && value is IFormattable formattable) | ||
| return formattable.ToString(null, _config.TypeCultures[type]); | ||
|
|
||
| if (type == typeof(Guid)) | ||
| return value.ToString(); | ||
|
|
||
| return value.ToString() ?? "null"; | ||
| } | ||
| } | ||
| } | ||
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.
проверка на null уже выше есть