Reputation: 5386
I have two classes
public class JobDataProvider
{
public List<Job> Get(int id){
List<Job> jobs = new List<Job>();
foreach(up_GetJobResult result in myDataContext.up_GetJob(id))
{
jobs.add(new Job(Id = result.Id, name = result.Name));
}
return jobs;
}
}//end class Job
public class PersondataProvider{
public List<Person> Get(int id){
List<Person> persons = new List<Persons>();
foreach(up_GetPersonsResult result in MyDataContext.up_GetPerson(id)){
persons.add(new Person(Id = result.Id, Name = result.Name, Surname = result.Surname));
}
return persons;
}
}end class Person
i want to create a generic method, something like this
public List<T> Get<T>(int id)
{
.. get data and return the list
}
Upvotes: 2
Views: 591
Reputation: 7426
Unless you want to do some super ugly reflection, you MUST add more metadata to your classes. This ideally would come in the form of interface implementation. With that information, you can actually do something with the type parameter of your Get method. This is a basic sample shows how you can then map DataProviders to type parameters. The Registry static class would have to be initialized at some point before being used.
// generic mechanism through which the Get method can lookup a specific provider
interface IDataProvider<T> {
List<T> Get(int id);
}
// implement the generic interface
public class JobDataProvider : IDataProvider<Job> {
// existing stuff
}
// implement the generic interface
public class PersondataProvider : IDataProvider<Person> {
// existing stuff
}
// this class holds the method originally desired
public static class Helper {
public static List<T> Get<T>(int id) {
return Registry.Get<IDataProvider<T>>().Get(id);
}
}
// this functions as the glue/mapping between type parameters
// and specific, concrete data providers
public static class Registry {
private static Dictionary<Type, Func<object>> _entries;
public static T Get<T>() where T: class {
return _entries[typeof(T)]() as T;
}
public static void Register<T>(Func<T> item) {
_entries.Add(typeof(T), () => item() as object);
}
}
Initialization code:
void Init() {
Registry.Register<IDataProvider<Job>>(() => new JobDataProvider());
Registry.Register<IDataProvider<Person>>(() => new PersondataProvider());
}
Usage:
var job15 = Helper.Get<Job>(15);
var person2 = Helper.Get<Person>(2);
Upvotes: 0
Reputation: 38025
You didn't exactly ask a question, but I'll see if I can guess what you are asking. You want a generic method where you can specify the type you want returned and an ID and have the generic method figure out where to get the data from.
You can create a dictionary with the key being the type (T) and the value being the list you want returned or, perhaps, an instance of an interface that returns the list you want (if the list is dynamic and you don't want to store it in multiple places).
Here is an interface you might try (you will obviously want to add more error handling). Of course this example assumes that you not only have a explicit interface (IDataProvider) but also an implicit interface (IDataProvider.Get must return a properly typed generic List).
public interface IDataProvider
{
IEnumerable Get(int id);
}
public class JobDataProvider
: IDataProvider
{
public List<Job> Get(int id)
{
var jobs = new List<Job>();
// load jobs
return jobs;
}
IEnumerable IDataProvider.Get(int id)
{
return Get(id);
}
}
public class PersonDataProvider
: IDataProvider
{
public List<Person> Get(int id)
{
var people = new List<Person>();
// load people
return people;
}
IEnumerable IDataProvider.Get(int id)
{
return Get(id);
}
}
public class ItemDataProvider
{
private Dictionary<Type, IDataProvider> mProviders = new Dictionary<Type, IDataProvider>();
public void RegisterProvider(Type type, IDataProvider provider)
{
mProviders.Add(type, provider);
}
public List<T> Get<T>(int id)
{
var data = mProviders[typeof(T)].Get(id);
return (List<T>)data;
}
}
public class Job
{
}
public class Person
{
}
Upvotes: 2
Reputation: 64635
I'm still hazzy on the nature of the up_GetJobResult class and the up_GetPersonResult classes. Do these share a base class? If the results from MyDataContext always derive from the same base class, that makes it a bit easier:
/// <summary>
/// Interface used on the individual classes that controls
/// how the class will load it's data.
/// </summary>
public interface ILoadable
{
/// <summary>
/// Again, I did not know what type of return value comes back from MyDataContext
/// If the results are always of the same type or if they derive from the same
/// base class, then it makes it simpler.
/// </summary>
void Load( ResultBaseClass result );
}
public class Job : ILoadable
{
public int Id { get; set; }
public string Name { get; set; }
public void Load( ResultBaseClass result )
{
var jobResult = result as up_GetJobResult;
if ( jobResult == null )
return;
Id = jobResult.Id;
Name = jobResult.Name;
}
}
public static class MyDataContext
{
public static IList<ResultBaseClass> up_GetPerson( int id );
public static IList<ResultBaseClass> up_GetJobResult( int id );
}
public class Person : ILoadable
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public void Load( ResultBaseClass result )
{
var personResult = result as up_GetPersonResult;
if ( personResult == null )
return;
Id = personResult.Id;
Name = personResult.Name;
Surname = personResult.Surname;
}
}
public abstract class MyProvider<T> where T : ILoadable, new()
{
/// <summary>
/// Create a method only visible to derived classes which takes a delegate for the specific
/// routine that should be called to retrieve data.
/// </summary>
protected List<T> Get( int id, Func<int, IList<ResultBaseClass>> getRoutine )
{
var result = new List<T>();
foreach ( var resultInstance in getRoutine( id ) )
{
var item = new T();
item.Load( resultInstance );
result.Add( item );
}
return result;
}
}
public class JobDataProvider : MyProvider<Job>
{
public List<Job> Get( int id )
{
return base.Get( id, MyDataContext.up_GetJobResult );
}
}
public class PersonDataProvider : MyProvider<Person>
{
public List<Person> Get( int id )
{
return base.Get( id, MyDataContext.up_GetPerson );
}
}
Upvotes: 0
Reputation: 986
You need an interface
public interface IProvider<TKey, TValue>
{
IList<TValue> Get(TKey id);
}
Next, your public classes need to implement this interface:
public class JobDataProvider : IProvider<Job, int>
{
public IList<Job> Get(int id)
{
}
}
Now you have your repeatable pattern you were looking for.
Upvotes: 0
Reputation: 5945
Unless there is a common interface or link between what you want to pass as T, and the DataContext which has the stored procedures, this may be hard to do.
However, you might be able to utilize the DynamicObject capability in .NET 4.0 to do this. If your MyDataContext object was a DynamicObject, you could use the convention that your data retrieval method is always up_GetFoo where Foo is also your return Type in concert with TryGetMember to do this.
Upvotes: 1
Reputation: 16926
Here are some possibilities.
IEnumerable<T> Get<T>(int id) { } // returns an IEnumerable containing the data
// can use yield return inside to eable deferred execution
IList<T> Get<T>(int id) { } // returns a list
T Get<T>(int id) { } // returns a single object
Upvotes: 0