#c# #generics #interface #return-type
#c# #обобщения #интерфейс #возвращаемый тип
Вопрос:
У меня есть библиотека доступа к данным, которую я хотел бы возвращать в различных форматах данных (XML, Json, DataTable). Я пытался использовать дженерики для достижения этой цели.
public interface IDBInteractor<T>
{
T ExecuteDSQuery(string myQuery)
}
public class DBInteractorDT : IDBInteractor<DataTable>
{
public DataTable ExecuteDSQuery(string myQuery)
{
return new DataTable();
}
}
public class DBInteractorJson : IDBInteractor<JsonString>
{
public JsonString ExecuteDSQuery(string myQuery)
{
return new JsonString();
}
}
У меня возникли проблемы с вызовом правильного метода. В идеале я бы объявил что-то вроде
SomeClass<DataTable> dt = new SomeClass<DataTable>();
SomeClass<JsonString> js = new SomeClass<JsonString>();
DataTable myDT = dt.ExecuteDSQuery(myQuery);
JsonString myJson = js.ExecuteDSQuery(myQuery);
Я не уверен, как объявить SomeClass. Я знаю, что мог бы сделать что-то вроде
public class SomeClass<T> where T : IDBInteractor <T>
{
public T ExecuteQuery(T dtobject, string myQuery)
{
return dtobject.ExecuteDSQuery(myQuery);
}
}
Но я не хочу передавать экземпляр объекта (dtobject) при каждом вызове метода.
Комментарии:
1. Почему
DBInteractorJson
‘sExecuteDSQuery
возвращает строку? Он должен возвращатьJsonString
2. Сравните
SomeClass<DataTable> dt = new SomeClass<DataTable>();
иpublic class SomeClass<T> where T : IDBInteractor <T>
. НоDataTable
это неIDBInteractor <T>
Ответ №1:
Что именно вы пытаетесь сделать? Этот код работает нормально:
using System.Data;
namespace ConsoleApplication7
{
internal class Program
{
private static void Main(string[] args)
{
IDBInteractor<DataTable> dt = new SomeClass<DataTable>(new DBInteractorDT());
IDBInteractor<JsonString> js = new SomeClass<JsonString>(new DBInteractorJson());
/*
or you can write
IDBInteractor<DataTable> dt = new DBInteractorDT();
IDBInteractor<JsonString> js = new DBInteractorJson();
*/
DataTable myDT = dt.ExecuteDSQuery("");
JsonString myJson = js.ExecuteDSQuery("");
}
}
public interface IDBInteractor<T>
{
T ExecuteDSQuery(string myQuery);
}
public class DBInteractorDT : IDBInteractor<DataTable>
{
#region IDBInteractor<DataTable> Members
public DataTable ExecuteDSQuery(string myQuery)
{
return new DataTable();
}
#endregion
}
public class DBInteractorJson : IDBInteractor<JsonString>
{
#region IDBInteractor<JsonString> Members
public JsonString ExecuteDSQuery(string myQuery)
{
return new JsonString();
}
#endregion
}
public class SomeClass<T> : IDBInteractor<T>
{
private IDBInteractor<T> interactor;
public SomeClass(IDBInteractor<T> interactor)
{
this.interactor = interactor;
}
public T ExecuteDSQuery(string myQuery)
{
return interactor.ExecuteDSQuery(myQuery);
}
}
public class JsonString
{
}
}
Комментарии:
1. Вы правы, я изначально ошибочно вызывал объект типа: DBInteractorDT<DataTable> dt = new DBInteractorDT();
Ответ №2:
если ваш универсальный параметр имеет конструктор без параметров, вы можете создать новый объект T();
но вы должны определить, что у вашего T должен быть конструктор без параметров, использующий универсальное ограничение new(), чтобы заставить это:
public class SomeClass<T> where T : IDBInteractor <T> , new()
Ответ №3:
Вы могли бы добавить ограничение new() в свое определение класса, чтобы ваш класс стал:
public class SomeClass<T> where T : IDBInteractor <T>, new()
{
public T ExecuteQuery(string myQuery)
{
return new T().ExecuteDSQuery(myQuery);
}
}
Затем вы можете выполнить любую настройку в общедоступном конструкторе без параметров.
Ответ №4:
Ваш SomeClass<T>
имеет зависимость от IDBInteractor<T>
. Вы могли бы добавить new()
ограничение, чтобы вы могли создавать экземпляр в SomeClass<T>
всякий раз, когда вам это нужно.
Но почему бы не использовать возможности depencency injection? Просто принять IDBInteractor<T>
в качестве параметра в конструкторе SomeClass<T>
?
Код
public class SomeClass<T> where T : IDBInteractor <T>
{
private IDBInteractor<T> _interactor;
public SomeClass(IDBInteractor<T> interactor)
{
_interactor = interactor;
}
public T ExecuteQuery(string myQuery)
{
return _interactor.ExecuteDSQuery(myQuery);
}
}
Смотрите также
http://www.theserverside.com/news/1321158/A-beginners-guide-to-Dependency-Injection
Ответ №5:
Я согласен с fix_likes_coding. Если вы хотите создать класс только для выполнения запроса, вы можете вместо этого посмотреть на методы расширения. Возможно, это не совсем вписывается в общую схему вещей, но может помочь, если вы хотите упростить задачу.
public static class InteractorUtils
{
public static T ExecuteQuery(this IDBInteractor<T> interactor, string myQuery)
{
return interactor.ExecuteDSQuery(myQuery);
}
}
и вы могли бы использовать это следующим образом:
IDBInteractor<DataTable> dt = new DBInteractorDT();
dt.ExecuteQuery("");