Проверка типа времени компиляции - PullRequest
0 голосов
/ 10 октября 2019

представьте универсальный класс B

public class B<T> : IB
{
   public void Foo(object parameter)
   {
      var param = (T)parameter;
      //...
   }
}

И класс A, который получает коллекцию B, переданную через его конструктор. Обратите внимание, что я использую интерфейс IB как тип там.

public class A
{
   public A(IEnumerable<IB> collectionOfBs) {}

}

Некоторое время спустя я хочу выполнить некоторый метод для класса A, скажем, foo, который будет принимать коллекцию объектов типа Tгде T - универсальный тип экземпляра B, переданного в конструктор. так что эти типы должны совпадать.

public void foo(IEnumerable<object> param)
{
   for (int i = 0; i < collectionOfBs.Count(); i++)
   {
     collectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
   }
}

Сейчас я передаю IEnumerable<object> и приводим к типу T внутри foo, это будет работать, но мне интересно, могу ли я проверить этот типвместо этого во время компиляции?

Любые идеи, если это возможно или нет? Спасибо

Ответы [ 2 ]

0 голосов
/ 10 октября 2019

Если вам нужна последовательная проверка универсальных типов, вам необходимо применять универсальные шаблоны последовательно. В настоящее время вы используете промежуточный подход: B<T> является общим, а IB - нет. Тогда у вас есть неуниверсальный класс A, который соединяется с неуниверсальным интерфейсом IB, но вы хотите проверить тип во время компиляции T, о котором оба, A и IB ничего не знают о(только для внутреннего приведения его к T). Это небольшая проблема.

Из использования ваших классов / интерфейса кажется очевидным, что вы не ожидаете смешанных реализаций IB в A, поэтому вы можете последовательно применятьпараметр универсального типа T для всех типов:

public class B<T> : IB<T>
{
   public void Foo(T parameter)
   {
      var param = parameter;
      //...
   }
}

public class A<T>
{
    public A(IEnumerable<IB<T>> collectionOfBs) {}

    public void foo(IEnumerable<T> param)
    {
       collectionOfBs.Zip(param, (b, t) => { b.Foo(t); return 0 });
    }
}

Обратите внимание, что я заменил ваш подход на for и ElementAt на Enumerable.Zip.

0 голосов
/ 10 октября 2019

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

Это не гарантирует, что TParam и T одинаковы, так как у вас не универсальный интерфейс, но он лучшийможет сделать, как я знаю, в соответствии с первым исследованием вашей проблемы ...

Потому что в C # нет оператора с бриллиантом, который позволял бы истинный общий полиморфизм для открытых типов.

    public interface IB
    {
      void Foo<TParam>(TParam parameter);
    }

    public class B<T> : IB
    {
      public void Foo<TParam>(TParam parameter)
      {
        var param = parameter;
        Console.WriteLine("param type: " + param.GetType().Name);
      }
    }

    public class A
    {
      private IEnumerable<IB> CollectionOfBs;

      public A(IEnumerable<IB> collectionOfBs)
      {
        CollectionOfBs = collectionOfBs;
      }

      public void Foo(IEnumerable<object> param)
      {
        if ( param.Count() < CollectionOfBs.Count() )
          throw new ArgumentException();
        for ( int i = 0; i < CollectionOfBs.Count(); i++ )
          CollectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
      }
    }

Метод испытания

    static void Test()
    {
      var listInstances = new List<IB> { new B<int>(), new B<double>(), new B<string>() };

      var container = new A(listInstances);

      var listParams = new List<object> { 2, 4.3, "test" };

      container.Foo(listParams);
    }

Выход

param type: Int32
param type: Double
param type: String

Соображения

Проблема здесьчто любой тип параметра с плохим соответствием может быть передан.

Например, с помощью Test () у вас может быть двойное число вместо первого целого числа, и это работает: вы получаете Double на вашем экземпляре Int32 ...

param type: Double
param type: Double
param type: String

Имея оператор Diamond <>, вы сможете использовать общий интерфейс и анализировать закрытый список созданных типов ... и ваш дизайн будет лучше пахнуть:

public interface IB<T>
{
  void Foo(T parameter);
}

public class B<T> : IB<T>
{
  public void Foo(T parameter)

  {
    var param = parameter;
    Console.WriteLine("param type: " + param.GetType().Name);
  }
}

public class A
{
  private IEnumerable<IB<>> CollectionOfBs;

  public A(IEnumerable<IB<>> collectionOfBs)
  {
    CollectionOfBs = collectionOfBs;
  }

  public void Foo(IEnumerable<object> param)
  {
    if ( param.Count() < CollectionOfBs.Count() )
      throw new ArgumentException();
    for ( int i = 0; i < CollectionOfBs.Count(); i++ )
    {
      CollectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
    }
  }
}

Следовательно, при этом любой неверно соответствующий тип параметра будетЯ выдвигаю исключение во время выполнения.

...