Динамический возвращаемый тип для метода .NET

#c# #generics

#c# #обобщения

Вопрос:

У меня есть веб-метод, который вызывает метод в DAL для выполнения процедуры по идентификатору и возвращает объект типа MyData.

 [WebMethod]
public MyData GetDataById(int id)
{
    DAL myDAL = new DAL();
    return myDAL.GetDataById(id);
}
  

Класс MyData выглядит следующим образом

 public class MyData
{        
    public string Name;
    public Data[] DataItems;     
}
  

и класс Data ,

 public class Data
{
    public string key;
    public string value;
}
  

Теперь это работало нормально до тех пор, пока мы не захотели вернуть немного сложных типов.

Например, DataTable или, возможно, что-то вроде структуры (или класса), содержащей широту, долготу и значение. Итак, очевидно, что класс Data не может содержать несколько значений или DataTable. (Он содержит две строки, ключ и значение).

Итак, что я на самом деле хочу, так это чтобы тип был универсальным. Поэтому я изменил его на…

 public class MyData<T>
{        
    public string Name;
    public T[] DataItems;     
}
  

Итак, я буду делать что-то подобное внутри myDAL.GetDataById , потому что тип возвращаемых данных отличается в зависимости от типа.

 if (GetTypeOfId(id) == "NormalData")
{
   MyData<Data> result = new MyData<Data>();
}
else if (GetTypeOfId(id) == "Map")
{
   MyData<MapData> result = new MyData<MapData>();
}
  

Но мне также нужно указать тип для подписи метода, который, к сожалению, обнаруживается ТОЛЬКО во время выполнения.

Как мне справиться с такой ситуацией?

Я чувствую, что использую дженерики для чего-то, для чего я не должен их использовать.

Или как обычно решается ситуация, когда тип обнаруживается только во время выполнения?

ОБНОВЛЕНИЕ: Наихудшим сценарием является использование разных вызовов веб-служб для получения обычных данных и картографических данных, которых я хотел бы избежать.

Комментарии:

1. Для какого метода вам нужно указать тип? Вы не можете сделать общедоступными MyData<T> GetDataById (идентификатор int)?

2. ДА. Для вызова веб-службы, а также метода в DAL.

3. @Cilvic: У вас действительно может быть общий WebMethod ?

Ответ №1:

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

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

Если вам действительно нужен только один вызов веб-службы, вы могли бы попросить свой веб-метод просто вернуть байт [] (созданный с помощью BinaryFormatter) или строку (созданную, скажем, с помощью XmlSerializer), а затем десериализовать это на стороне вашего клиента, но это означает, что у вас должны быть одинаковые классы с обеих сторон (или у вас должен быть пользовательский код десериализации), и ваш веб-сервис не может легко использоваться несколькими клиентами.

Ответ №2:

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

Если вы используете IData вместо универсального типа в качестве возвращаемого значения, вы сможете извлечь встроенные данные с помощью ret.GetValue<MyData>() . И если вы зададите тип при создании Data<T> , вы также сможете запрашивать его.

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

 public interface IData {
    type Type { get; set; }
    string Name { get; set; }
    T GetValue<T>();
}

public class Data<T> : IData
{

    public Type Type { get; set; }
    public string Name { get; set; }
    public T Value { get; set; }
    public Tret GetValue<Tret>() {
        return (Tret)(Object)Value;
    }
}
  

Ответ №3:

Ответ был довольно простым и глупым с моей стороны, что я не подумал об этом раньше. Я только что создал родительский класс и заставил Data и все остальные требуемые классы наследоваться от него.