I have the need to create a generic method to retrieve a specific kind of class that derives from System.Data.Services.Client.DataServiceContext
, I got some ideas how to deal with this but so far I'm stuck in the concept of generic co-variance, does this concept applies to this case at all? this is how my current code looks like :
public abstract class BaseODataProvider<T> where T : DataServiceContext, new()
{
public IApiSettings ApiSettings { get; set; }
public BaseODataProvider(IApiSettings ApiSettings = null)
{
this.ApiSettings = ApiSettings ?? new DefaultApiSettings();
}
public T GetContext()
{
var context = new T(new Uri(ApiSettings.ODataUrl));
context.IgnoreMissingProperties = true;
context.IgnoreResourceNotFoundException = true;
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(ApiSettings.LoginName + ":" + ApiSettings.Password));
context.SendingRequest +=
(object s, SendingRequestEventArgs e) =>
e.RequestHeaders.Add("Authorization", "Basic " + credentials);
return context;
}
}
As you can see, there is no way I can instantiate T with optional parameters, it says "cannot provide parameters when creating an instance of a type parameter 'T'
", however I would like to find out a way to resolve what URI is needed to create the oDataContext based on the type of T
, so my expected instances would be something like this:
GetContext<MyContext1>().Table1.Where(x=>x.Id == 1);
GetContext<MyContext2>().Table2.FirstOrDefault();
Any help works!
You can instantiate an object of a generic type with parameters using reflection.
public T GetContext()
{
Uri myUri = new Uri(ApiSettings.ODataUrl);
Type contextType = typeof(T);
DataServiceContext context = (T)Activator.CreateInstance(contextType, myUri);
// Do whatever
return context;
}
The second argument of Activator.CreateInstance
is an array of type object
, so you can pass in whatever number or type of arguments the constructor requires. To make the above code work, all of the T
types you use have to have a constructor with the same signature, like this:
public class MyContext1 : DataServiceContext
{
public MyContext1(Uri uri)
{
// Do whatever
}
}
public class MyContext2 : DataServiceContext
{
public MyContext2(Uri uri)
{
// Do whatever
}
}
You're not limited to a single parameter either - this works for constructors with any number of parameters. Just make sure that you're using the same number and type of arguments for each class that you instantiate this way.