NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET 매크로 프로그램 만들기. (배열 연산을 쉽게 처리할 수 있는 기능)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 지금까지 배열에 관련된 내용들을 다루면서 닷넷과 엔지엠 매크로에서 배열을 어떻게 처리하는지 알아봤습니다. 아무래도 코딩으로 처리할 수 있는게 다양하고 원하는데로 조작할 수 있는데요. 엔지엠 매크로는 GUI 방식으로 배열을 조작해야 하기 때문에 일부 기능들은 처리하기가 곤란한 것들이 있습니다. 이런 경우를 대비해서 커스텀 액션을 만들어서 사용할 수 있습니다. 이와 관련된 내용은 나중에 자세하게 알아보기로 하고, 기능 확장 보다는 기본 제공하는 내용에 대해 알아보도록 하겠습니다.

     

    우선, 아래와 같이 Expression 카테고리에 ArrayOperationModel을 추가 했습니다. 명칭은 배열 연산입니다.

    RE3ESOK.png

     

     

    함수 상자의 표현식 안에 들어갈거예요.

    WMNHrnk.png

     

     

    자~ 이제 코딩을 해봅시다. 배열의 값들을 모두 연산에 사용해야 하기 때문에 일반적인 사칙연산과는 다르게 배열에 있는 모든 값을 가져와야 합니다. 아래 ArrayData는 변수로부터 가져와야 하는 값입니다. 따라서, 카테고리가 동작이 아닌 배열로 되어 있습니다.

    public class ArrayOperationModel : BaseModel
    {
        [NonSerialized]
        private string[]? _datas;
    
        [LocalizedCategory("Array")]
        [LocalizedDisplayName("RepeatData")]
        [LocalizedDescription("RepeatData")]
        [Browsable(true)]
        [DefaultValue(null)]
        public string[]? ArrayData { get { return _datas; } set { _datas = value; } }

     

    카테고리는 어느정도 논리적인 부분을 시각적으로 인지할 수 있도록 하는 도우미와 같은 값입니다. 우리가 어떤 동작을 만들 때는 동작 카테고리에 설정들이 있고, 이 동작이 수행된 후 결과로 나온 값들은 데이터입니다. 그 외에 옵션이나 확장 기능들도 카테고리별로 세분화되어 있는데요. 이를 통해서 좀 더 쉽고 빠르게 액션을 원하는 방향으로 동작시킬 수 있게됩니다. 

     

    아래는 배열 연산에 필요한 필 수 입력 값들입니다. 일부 옵션에 따라서 사용되지 않는 값도 있는데요. 이런 부분들은 아래 부분에서 테스트할 때 자세하게 알아볼께요.

    [LocalizedCategory("Action")]
    [LocalizedDisplayName("Operator")]
    [LocalizedDescription("Operator")]
    [Browsable(true)]
    [DefaultValue(typeof(Ai.Definition.ArrayOperator), "Plus")]
    public Ai.Definition.ArrayOperator Operator { get; set; } = Definition.ArrayOperator.Plus;
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("DecimalPlaces")]
    [LocalizedDescription("DecimalPlaces")]
    [Browsable(true)]
    [DefaultValue(0)]
    public int DecimalPlaces { get; set; }
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("FormulaRound")]
    [LocalizedDescription("FormulaRound")]
    [Browsable(true)]
    [DefaultValue(typeof(Ai.Definition.RoundType), "None")]
    public Ai.Definition.RoundType FormulaRound { get; set; } = Definition.RoundType.None;
    
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("Separator")]
    [LocalizedDescription("Separator")]
    [Browsable(true)]
    [DefaultValue(null)]
    public string? Separator { get; set; }

     

    위 속성에서 중요한 부분은 배열 연산자 옵션입니다. 아래 연산자에 따라서 Execute에서 로직을 분기하고, 처리 해줍니다.

    public enum ArrayOperator
    {
        Plus = 0,
        Minus = 1,
        Multiply = 2,
        Divide = 3,
        Average = 4,
        Median = 5,
        SortByMedian = 6,
        NumberSortByMedian = 7,
        Concatenate = 50
    }

     

    코드는 간단한데요. 배열안에 어떤 값이 들어올지 알 수 없기 때문에 기본적으로 숫자와 문자로 구분해놓고, 처리하도록 코딩되어 있습니다. 만약, 숫자와 문자 형식이 아닌 다른 형식이 들어온다면 이 액션은 정상 동작하지 않을겁니다. 동작하더라도 의도하지 않은 이상한 값이 나올 가능성도 큽니다.

    public override string? Execute(IPlayer player)
    {
        var id = base.Execute(player);
        double result = 0d;
    
        switch (Operator)
        {
            case Definition.ArrayOperator.Plus:
                result = ArrayData.Where(s => double.TryParse(s, out _)).Sum(s => double.Parse(s));
                break;
            case Definition.ArrayOperator.Minus:
                var numbers = ArrayData.Where(s => double.TryParse(s, out _)).Select(s => double.Parse(s)).ToList();
                var left = numbers.FirstOrDefault();
                numbers.RemoveAt(0);
    
                foreach (var right in numbers)
                    left -= right;
    
                result = left;
                break;
            case Definition.ArrayOperator.Multiply:
                numbers = ArrayData.Where(s => double.TryParse(s, out _)).Select(s => double.Parse(s)).ToList();
                left = numbers.FirstOrDefault();
                numbers.RemoveAt(0);
    
                foreach (var right in numbers)
                    left *= right;
    
                result = left;
                break;
            case Definition.ArrayOperator.Divide:
                numbers = ArrayData.Where(s => double.TryParse(s, out _)).Select(s => double.Parse(s)).ToList();
                left = numbers.FirstOrDefault();
                numbers.RemoveAt(0);
    
                foreach (var right in numbers)
                    left /= right;
    
                result = left;
                break;
            case Definition.ArrayOperator.Average:
                numbers = ArrayData.Where(s => double.TryParse(s, out _)).Select(s => double.Parse(s)).ToList();
                result = numbers.Sum() / numbers.Count();
                break;
            case Definition.ArrayOperator.Median:
                Result = ArrayData[ArrayData.Length / 2];
                break;
            case Definition.ArrayOperator.SortByMedian:
                var sortedString = ArrayData.OrderByNatural(o => o).ToArray();
                Result = sortedString[sortedString.Length / 2];
                break;
            case Definition.ArrayOperator.NumberSortByMedian:
                numbers = ArrayData.Where(s => double.TryParse(s, out _)).Select(s => double.Parse(s)).ToList();
                var sortedNumber = numbers.OrderByNatural(o => o).ToArray();
                Result = sortedNumber[sortedNumber.Length / 2].ToString();
                break;
            case Definition.ArrayOperator.Concatenate:
                Result = string.Join(Separator, ArrayData);
                break;
        }
    
        return id;
    }

     

    아직 몇가지 기능들은 구현조차 되지 않았는데요. 앞으로 개발하게 될 숫자 형식의 데이터를 변환하는 과정에서 필요한 모든 것들을 모아서 한번에 처리할 생각입니다. 숫자를 처리할 때 몇가지 공통적인 부분들이 있는데요. 이것들을 각각의 모델에서 처리하기 보다는 공통 모듈 또는 라이브러리에서 처리하도록 하면 코드 재사용성도 좋아지고 유지보수도 쉬워집니다. 너무 당연한 이야기인가요? ㅎㅎ

     

    이제 테스트를 해볼건데요. 적절하게 데이터를 채우고, 연산이 이루어지는지 확인 해볼께요.

     

     

    이 글이 도움이 되셨다면~ 커피 한잔이라도 후원 부탁드립니다^^

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.