Есть ли способ упростить использование нескольких «если» внутри друг друга? - PullRequest
0 голосов
/ 20 июня 2020

Вот пример того, что я имею в виду. Код работает, но мне интересно, есть ли другой способ реализовать ту же функциональность:

        if (App.ShowIcons)
        {
            if (App.devIsIOS)
            {
                this.Children.Add(FR1, 0, 0);
                this.Children.Add(GT, 1, 0);
                this.Children.Add(FR2, 2, 0);
            }
            else
            {
                this.Children.Add(FR1, 0, 0);
                this.Children.Add(GT, 1, 0);
                this.Children.Add(CE, 2, 0);
            }
        }
        else
        {
            if (App.devIsIOS)
            {
                this.Children.Add(GT, 0, 0);
                this.Children.Add(FR2, 1, 0);
            }
            else
            {
                this.Children.Add(GT, 0, 0);
                this.Children.Add(CE, 1, 0);
            }
        }

Обновление: вот проблема, которую я получаю при попытке реализовать один из ответов:

введите описание изображения здесь

Ответы [ 4 ]

4 голосов
/ 20 июня 2020

Одним из возможных способов уменьшения вложенности является использование кортежей и переключателя

switch (ShowIcons, devIsIOS)
{
    case (true, true):
        Children.Add(FR1, 0, 0);
        Children.Add(GT, 1, 0);
        Children.Add(FR2, 2, 0);
        break;
    case (true, false):
        Children.Add(FR1, 0, 0);
        Children.Add(GT, 1, 0);
        Children.Add(CE, 2, 0);
        break;
    case (false, true):
        Children.Add(GT, 0, 0);
        Children.Add(FR2, 1, 0);
        break;
    case (false, false):
        Children.Add(CE, 2, 0);
        Children.Add(GT, 0, 0);
        Children.Add(CE, 1, 0);
        break;
    default:
        throw new Exception("");
}

, если этот logi c не используется слишком много в приложении, тогда его можно использовать. Но если этот logi c является динамическим c и может быть изменен в будущем, тогда попробуйте написать свой код объектно-ориентированным способом и обработать logi c, используя polymorphi c вместо ветвления (if-else), как показано в это блог .

2 голосов
/ 20 июня 2020

Удаление повторяющегося вызова из вложенных операторов if может сделать все выражение короче и чище

if (App.ShowIcons)
{
    Children.Add(FR1, 0, 0);
    Children.Add(GT, 1, 0);
    Children.Add(App.devIsIOS ? FR2 : CE, 2, 0);
}
else
{
    Children.Add(GT, 0, 0);
    Children.Add(App.devIsIOS ? FR2 : CE, 1, 0);
}

Согласно комментариям, если значения FR2 и CE имеют разные типы, вы должны привести их к общему базовому типу, например View в вашем случае Children.Add(App.devIsIOS ? (View)FR2 : CE, 1, 0);

2 голосов
/ 20 июня 2020

На этот вопрос сложно ответить, есть много способов реализовать подобные вещи, и тогда это становится вопросом личных предпочтений.

Тем не менее, этот лог c можно упростить и реализовать без использования вложенных предложений if / else, которые, судя по названию, я надеюсь, именно то, что вы ищете:

var index = 0;
if (App.ShowIcons)
    children.Add(FR1, index++, 0);
children.Add(GT, index++, 0);
children.Add(App.devIsIOS ? FR2 : CE, index, 0);
1 голос
/ 20 июня 2020

Мне нравится Муджахид Дауд Хан ответ за использование шаблонов C# 8.0. Для полиморфного c способа, я считаю, что статья - это TLDR: P

На базовом уровне c мы можем сделать что-то вроде этого:

using System;
using System.Collections.Generic;

namespace ConsoleApp4
{
    class Program
    {
        static void Main()
        {
            var builder = new IconSelectorBuilder();

            Console.WriteLine($"{nameof(Device.DevIsIOS)}, false");
            foreach (var item in builder.Build(Device.DevIsIOS, false).GetIcons())
            {
                Console.WriteLine(item);
            }

            Console.WriteLine($"{nameof(Device.DevIsIOS)}, true");
            foreach (var item in builder.Build(Device.DevIsIOS, true).GetIcons())
            {
                Console.WriteLine(item);
            }

            //Console.WriteLine($"{nameof(Device.Other)}, false");
            //foreach (var item in builder.Build(Device.Other, false).GetIcons())
            //{
            //    Console.WriteLine(item);
            //}

            //Console.WriteLine($"{nameof(Device.Other)}, true");
            //foreach (var item in builder.Build(Device.Other, true).GetIcons())
            //{
            //    Console.WriteLine(item);
            //}
        }
    }

    public enum Device
    {
        DevIsIOS,
        Other
    }

    public class IconSelectorBuilder
    {
        public IIconSelector Build(Device device, bool showIcons)
        {
            return device switch
            {
                Device.DevIsIOS => new DevIsIOSIconSelector(showIcons),
                _ => new OtherIconSelector(showIcons),
            };
        }
    }

    public interface IIconSelector
    {
        public bool ShowIcons { get; set; }

        IEnumerable<Icon> GetIcons();
    }

    public abstract class IconSelectorBase : IIconSelector
    {
        public bool ShowIcons { get; set; }

        protected IconSelectorBase(bool showIcons)
        {
            ShowIcons = showIcons;
        }

        protected abstract IEnumerable<Icon> GetHideIcons();

        protected abstract IEnumerable<Icon> GetShowIcons();

        public IEnumerable<Icon> GetIcons() => ShowIcons ? GetShowIcons() : GetHideIcons();
    }


    public sealed class DevIsIOSIconSelector : IconSelectorBase
    {
        public DevIsIOSIconSelector(bool showIcons) : base(showIcons)
        {
        }

        protected override IEnumerable<Icon> GetHideIcons()
        {
            yield return new Icon
            {
                IconType = IconType.GT,
                MyProperty1 = 0,
                MyProperty2 = 0,
            };

            yield return new Icon
            {
                IconType = IconType.FR2,
                MyProperty1 = 1,
                MyProperty2 = 0,
            };
        }

        protected override IEnumerable<Icon> GetShowIcons()
        {
            yield return new Icon
            {
                IconType = IconType.FR1,
                MyProperty1 = 0,
                MyProperty2 = 0,
            };

            yield return new Icon
            {
                IconType = IconType.GT,
                MyProperty1 = 1,
                MyProperty2 = 0,
            };

            yield return new Icon
            {
                IconType = IconType.FR2,
                MyProperty1 = 2,
                MyProperty2 = 0,
            };
        }
    }

    public sealed class OtherIconSelector : IconSelectorBase
    {
        public OtherIconSelector(bool showIcons) : base(showIcons)
        {
        }

        protected override IEnumerable<Icon> GetHideIcons()
        {
            // TODO
            throw new NotImplementedException();
        }

        protected override IEnumerable<Icon> GetShowIcons()
        {
            // TODO
            throw new NotImplementedException();
        }
    }

    public class Icon
    {
        public IconType IconType { get; set; }

        public int MyProperty1 { get; set; }

        public int MyProperty2 { get; set; }

        public override string ToString() => $"{IconType}, {MyProperty1}, {MyProperty2}";
    }

    public enum IconType
    {
        FR1,
        GT,
        FR2,
        CE
    }
}

Идея состоит в том, чтобы создать IconSelectorBuilder и укажите такие параметры, как App.devIsIOS / whatever, App.ShowIcons / whatever (я предположил bool). Затем мы создаем правильный класс, который наследуется от IconSelectorBase, который предоставляет logi c для параметра bool (App.ShowIcons / 'any'). Тогда соответствующий класс вернет правильные значки.

Вывод:

DevIsIOS, false
GT, 0, 0
FR2, 1, 0
DevIsIOS, true
FR1, 0, 0
GT, 1, 0
FR2, 2, 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...