Лучшая реализация для C# Generi c метода, который должен нацеливаться на различные свойства в зависимости от типа класса, передаваемого в - PullRequest
2 голосов
/ 02 марта 2020

Итак, у меня есть метод, который анализирует входящее поле и, в зависимости от его длины, ему нужно записать в одно или несколько полей (не спрашивайте ... Требуется устаревший код Db2). В настоящее время мы внедрили этот метод для каждого класса, в котором это требуется, и я хотел написать обобщенный метод c, который я до некоторой степени выполнил. Проблема заключается в том, что, хотя метод анализа поля адреса одинаков для каждого объекта, используемые имена свойств различаются в зависимости от того, к какому классу он относится.

Затем необходимо проверить тип передаваемого объекта, а затем выполнить двойное приведение (ClassType) (объект), чтобы иметь возможность доступа к свойствам и установить их правильно, а затем выполнить еще одно двойное приведение (T ) (объект) для возврата списка generi c.

Это неэффективно и в основном несколько противоречит цели использования дженериков для начала. Есть ли лучший способ получить ту же функциональность без необходимости проверок типов и двойного приведения, чтобы иметь доступ к свойствам класса?

public List<T> ParseLongNameStreetName<T>(List<T> myList)
        {
            myList.ForEach(item =>
            {
                if (item.GetType() == typeof(DP1)) {
                    DP1 castItem = (DP1)(object)item;
                    dynamic streetName = ParsedStreetName(castItem.MA1 + " " + castItem.MA2);

                    castItem.MA1 = streetName.add1;
                    castItem.MA2 = streetName.add2;
                    castItem.MA3 = streetName.add3;

                    item = (T)(object)castItem;
                }

                else if (item.GetType() == typeof(DI1))
                {
                    DI1 castItem = (DI1)(object)item;
                    dynamic streetName = ParsedStreetName(castItem.MA1 + " " + castItem.MA2);

                    castItem.MA1 = streetName.add1;
                    castItem.MA2 = streetName.add2;
                    castItem.MA3 = streetName.add3;

                    item = (T)(object)castItem;
                }
                else if (item.GetType() == typeof(DW1))
                {
                    DW1 castItem = (DW1)(object)item;
                    dynamic streetName = ParsedStreetName(castItem.AD1 + " " + castItem.AD2);

                    castItem.AD1 = streetName.add1;
                    castItem.AD2 = streetName.add2;
                    castItem.AD3 = streetName.add3;

                    item = (T)(object)castItem;
                }
            });

            return myList;
        }



private dynamic ParsedStreetName(string address)
        {
            string add1 = string.Empty;
            string add2 = string.Empty;
            string add3 = string.Empty;

            int addLen = address.Length;
            try
            {
                add1 = addLen > 30 ? address.Substring(0, 30) : address.Substring(0, addLen);
                add2 = addLen > 30 ? addLen > 60 ? address.Substring(29, 30) : address.Substring(30, addLen - 30) : "";
                add3 = addLen > 60 ? address.Substring(59, addLen - 60) : "";
            } catch(Exception ex)
            {
                Console.WriteLine(ex);
            }


            return new { add1, add2, add3 };
        }

Ответы [ 2 ]

1 голос
/ 02 марта 2020

Я бы, вероятно, подумал о том, чтобы адреса происходили от объекта базового адреса, который имеет типичные имена для свойств и / или, возможно, переопределяемый метод для установки соответствующих деталей. Ваш синтаксический анализатор может обрабатывать любую переменную сущность как базовый тип адреса и устанавливать свойства, и унаследованная реализация получит указанные c имена:

public class BaseAddress{
  protected string _buildingName;
  protected string _zipCode;

  public void SetAll(string b, string z){ // call this in your parser 
    _buildingName = b;
    _zipCode = z;
  }
}

public class WorkAddress:BaseAddress{
  public string Factory => _buildingName;
  public string PostCode => _zipCode;
}

public class HomeAddress:BaseAddress{
  public string HouseName => _buildingName;
  public string Zip => _zipCode;
}

Может даже иметь смысл встроить процедуру синтаксического анализа в базовый класс, добавляя переопределения только там, где есть существенное различие в операции

В этом смысле вам не нужно иметь метод generi c, который принимает все ваши различные типы адресов, когда вы можете иметь методы что взять BaseAddress. Я пропустил свойства для BaseAddress, но если вы будете работать с BaseAddress таким образом, было бы целесообразно добавить их - это было просто «мой контекст БД ожидает, что фабричные адреса, хранящиеся в фабричной таблице, будут иметь эти столбцы и домашнюю страницу». адреса должны иметь эти столбцы .. "


В качестве альтернативы, что-то вроде Automapper может быть настроено так, чтобы иметь возможность отображать несколько различных типов объектов адреса на общий и обратно, особенно если это проблема, когда вы пересекаете границу прикладных слоев

1 голос
/ 02 марта 2020

То, что вы пытаетесь сделать, - это назначать адреса разным свойствам (зависит от разных типов). Для этого вам не нужно использовать тип generi c, вам просто нужно создать интерфейс

   public interface IAddressAssignable
   {
      string GetRawAddress();
      void AssignAddresses(string add1, string add2, string add3);
   }

Make all 3 (DP1, DI1, DWXP111) реализует этот интерфейс (с разными логиками * 1007) * (разные свойства). Тогда в вашем ForEach ()

myList.ForEach(item =>
{
    dynamic streetName = ParsedStreetName(item.GetRawAddress());
    item.AssignAddresses(streetName.add1, streetName.add2, streetName.add3);
}
...