Conversation
| person.Phone = new Phone {Name = "Смартфон Vivo", Owner = person}; | ||
|
|
||
| var printer = ObjectPrinter.For<Person>(); | ||
| var printer = ObjectPrinter.For<Person>() |
There was a problem hiding this comment.
Сейчас из интерфейса торчит куча методов. Пользоваться таким будет сложно. Давай подумаем, как можно убрать часть из этих вещей, чтобы они не торчали наружу. Тут пока вижу два способа - как-то изменить способ работы Serializaers(возможно вернуть логику внутрь конфига), либо закрыть внутренние методы ключевым словом internal, но тут возникнет проблема расширяемости.
There was a problem hiding this comment.
Тут ещё и доступен TrimStringToLength, который по факту должен быть доступен только для типа string
ObjectPrinting/PrintingConfig.cs
Outdated
| public readonly Dictionary<Type, CultureInfo> CustomCultureInfos; | ||
| public readonly Dictionary<string, ISerializer> PropertySerializers; | ||
| public readonly Dictionary<string, int> MaxStringLength; | ||
| public readonly HashSet<string> ExcludedProperties; |
There was a problem hiding this comment.
Давай для всех полей сделаем модификаторы private, а также заиспользуем ридонли коллекции (IReadOnlyDictionary, IReadOnlySet). Следует инкапсулировать данные, которые нужны для внутренней логики, а доступ к ним осуществлять через методы
ObjectPrinting/PrintingConfig.cs
Outdated
| public PrintingConfig<TOwner> ExcludePropertyOfType<T>() | ||
| { | ||
| var tempSet = new HashSet<Type>(ExcludedTypes); | ||
| tempSet.Add(typeof(T)); |
There was a problem hiding this comment.
Тут можно добавить проверку на то, что данный тип уже есть в сете, если есть - не копировать сет
ObjectPrinting/PrintingConfig.cs
Outdated
| public PrintingConfig<TOwner> WithTypeSerializtionType<T>(ISerializer serializer) | ||
| { | ||
| var tempDict = new Dictionary<Type, ISerializer>(TypeSerializers); | ||
| tempDict.Add(typeof(T), serializer); |
There was a problem hiding this comment.
Здесь упадём с ошибкой, если данный тип уже есть в словаре. Кажется стоит это как-то обрабатывать. Ниже в методах та же проблема
ObjectPrinting/PrintingConfig.cs
Outdated
| ExcludedProperties); | ||
| } | ||
|
|
||
| public PrintingConfig<TOwner> TrimStringToLength(string propertyName, int length) |
There was a problem hiding this comment.
Тут должны давать этот метод вызывать только для строковых значений
ObjectPrinting/Serializers.cs
Outdated
| continue; | ||
| } | ||
|
|
||
| sb.Append(identation + propertyInfo.Name + " = " + |
There was a problem hiding this comment.
Вот эта строчка практически три раза повторяется в коде, с небольшими различиями. Может вынесем её в отдельный метод?
ObjectPrinting/Serializers.cs
Outdated
| } | ||
| } | ||
|
|
||
| public class GuidSerializer : ISerializer |
There was a problem hiding this comment.
Давай разнесём сериализаторы по разным файликам. А ещё, кажется это не сильно удобно - создавать отдельный класс, чтобы сериализовать поле. Может попробуем как-нибудь иначе построить контракт?
| private readonly PrintingConfig<TOwner> _config; | ||
| private Expression<Func<TOwner, TPropType>>? _propertySelector; | ||
|
|
||
| public PropertyPrintingConfig(PrintingConfig<TOwner> config, Expression<Func<TOwner, TPropType>>? propertySelector) |
There was a problem hiding this comment.
Этот Expression никак не валидируется, по факту я могу туда засунуть что угодно
| //3. Для числовых типов указать культуру | ||
| .SetTypeCulture<double>(CultureInfo.InvariantCulture) | ||
| //4. Настроить сериализацию конкретного свойства | ||
| .GetProperty(x => x.Name).SetSerializationType(new NameSerializer()) |
There was a problem hiding this comment.
Странное название GetProperty. Честно, по нему я не могу понять что именно он должен делать. Давай подумаем, как сделать более понятные названия
| } | ||
|
|
||
| [Test] | ||
| public void ExcludeTypeTest() |
There was a problem hiding this comment.
Тесты стоит писать по AAA, более понятные названия дать, а также лучше строковые значения в них более приятно оформить, не в одну строку
ObjectPrinting/Serializers.cs
Outdated
| public interface ISerializer | ||
| { | ||
| public Func<object?, int, int, string> SerializerFunc { get; } | ||
| public Func<object?, int, int, string> GetSerializerFunc => SerializerFunc; |
ObjectPrinting/Serializers.cs
Outdated
| public Func<object?, int, int, string> GetSerializerFunc => SerializerFunc; | ||
| } | ||
|
|
||
| public class Serializer : ISerializer |
There was a problem hiding this comment.
Кажется в этом классе теперь не сильно много смысла и вместо его использования можно было просто использовать Func
ObjectPrinting/Serializers.cs
Outdated
| public Func<object?, int, int, string> SerializerFunc { get; } | ||
| public Func<object?, int, int, string> GetSerializeFunc => SerializerFunc; | ||
|
|
||
| public Serializer(Func<object?, int, int, string> serializerFunc) |
There was a problem hiding this comment.
Контракт входной функции не понятен - требуется передать функцию от объекта, числа и числа. Без понимания как это используется другими классами не понять для чего нужны эти числа, да и в итоге они могут никак и не применяться. Если ты хотел всё-таки как-то это обыграть, то числа скорее должны были передаваться отдельно под понятными именами. То есть примерно так:
public Serializer(Func<object?, string> serializator, int identation, int deepnessLevel)
Но как мне кажется это не ответственность конкретного сериализатора работать с этими значениями
There was a problem hiding this comment.
Я решил просто ликвидировать и интерфейс, и этот класс, и оставить просто Func<>, обёрнутый в делегат. Что-то такое будет нормальным вариантом?
There was a problem hiding this comment.
Да, вполне. Либо можно оставить Func<object, string>. То и то будет норм вариантом в целом
| public static class PropertyPrintingConfigExtensions | ||
| { | ||
| public static PrintingConfig<TOwner> SetSerializationStyle<TOwner, TPropType> | ||
| (this PropertyPrintingConfig<TOwner, TPropType> propertyConfig, Serializer serializer) |
There was a problem hiding this comment.
Здесь почему-то с классом работаешь, а не с интерфейсом. Я не смогу сюда передать другой наследник ISerializer
| } | ||
|
|
||
| public PrintingConfig<TOwner> ParentConfig => config; | ||
| public Expression<Func<TOwner, TPropType>>? PropertySelector => propertySelector; |
There was a problem hiding this comment.
Я посидел-поделал, но мыслей, как это реализовать не пришло, кроме как попытаться убрать Extensions и сделать эти методы приватными, но тогда возникает другой вопрос: как мне ограничить вызов метода Trim только для строк, кроме как where T : string, ведь так тут нельзя. Как тут поступить стоит: развивать эту мысль, или подумать над другими способами?
There was a problem hiding this comment.
Так я не совсем про то. Сейчас у тебя торчат наружу свойства PropertyName, PropertySelector и ParentConfig. Это засоряет список, их стоит сделать приватными
There was a problem hiding this comment.
А вот в том и дело, что они у меня сейчас используются в расширениях, поэтому я и не могу придумать, как их спрятать
There was a problem hiding this comment.
Ага, понял. Попробуй подумать про принципы ООП и что из них мы можем использовать.
There was a problem hiding this comment.
👍, действительно тонко, я думал про это изначально, но что-то не так, видимо, сделал, и оно не сработало тогда
| { | ||
| [Test] | ||
| public void Demo() | ||
| public void DemonstrationTest() |
ObjectPrinting/PrintingConfig.cs
Outdated
| return sb.ToString(); | ||
| } | ||
|
|
||
| private string SerializeDictionaryElement(object obj, int deepnessLevel) |
There was a problem hiding this comment.
А не логичнее тут работать с KeyValuePair или чем-то более удобным? Сейчас из-за этого приходится тебе хардкодить доступ к объектам в паре
| return deepnessExceededString; | ||
| var type = obj.GetType(); | ||
| var key = type.GetProperty("Key")!.GetValue(obj); | ||
| var value = type.GetProperty("Value")!.GetValue(obj); |
There was a problem hiding this comment.
На значения словаря не будут применяться правила сериализации?
| if (IsDeepnessOverflow(deepnessLevel)) | ||
| return deepnessExceededString; | ||
| var type = obj.GetType(); | ||
| var key = type.GetProperty("Key")!.GetValue(obj); |
| @@ -1,3 +1,3 @@ | |||
| using System; | |||
|
|
|||
| namespace ObjectPrinting.Tests | |||
There was a problem hiding this comment.
Стоит добавить в эти классы поля, приватные свойства и т.д., чтобы их тоже проверять в тестах. Сейчас у тебя не сериализуются публичные поля.
There was a problem hiding this comment.
👍 (на приватные поля и свойства добавил отдельный тест, сделал Age публичным полем, теперь сериализуется)

@tripples25
Выполнил минимальные требования по задаче