C# Generics abuse? - c#

I can't figure out why I am getting the error cannot be used as type parameter 't' in the generic type or method...There is no implicit reference conversion from...
Here is my entire piece of code (simplified):
The problem is on the line RefreshLocalListFromLocalStore(TestDataObjectTable);
using System;
using Microsoft.WindowsAzure.MobileServices;
using Microsoft.WindowsAzure.MobileServices.SQLiteStore;
using Microsoft.WindowsAzure.MobileServices.Sync;
public class TestDataObject
{
#region Properties
public string Id { get; set; }
#endregion
}
public class TestDatabaseManager
{
public MobileServiceClient Client;
private IMobileServiceSyncTable<TestDataObject> TestDataObjectTable;
public TestDatabaseManager()
{
CurrentPlatform.Init();
Client = new MobileServiceClient("SomeUrl");
var store = new MobileServiceSQLiteStore("SomePath");
store.DefineTable<TestDataObject>();
TestDataObjectTable = Client.GetSyncTable<TestDataObject>();
RefreshLocalListFromLocalStore(TestDataObjectTable);
}
#region Methods
public async void RefreshLocalListFromLocalStore<T>(T table) where T : IMobileServiceSyncTable<T>
{
try
{
await table.ToListAsync();
}
catch (Exception e)
{
}
}
#endregion
}

Your generic constraint is probably wrong. Use the following declaration for RefreshLocalListFromLocalStore:
public async void RefreshLocalListFromLocalStore<T>(IMobileServiceSyncTavble<T> table)
In your declaration, the table should have been a table of tables, which does not make sense. You can use the generics constraints still to limit what kind of elements you want to have for your table, for example if the elements in the table should be entities complying with some IEntity interface.
public async void RefreshLocalListFromLocalStore<T>(IMobileServiceSyncTavble<T> table) where T : IEntity

The problem is you're using T with constraint of Type IMobileServiceSyncTable<T> where T is again of Type IMobileServiceSyncTable<T>.
Use constraints on the type for generic interface
public async void RefreshLocalListFromLocalStore<T>(IMobileServiceSyncTable<T> table)
where T : TestDataObject
{
}
See specification of using Type constraints.

T is IMobileServiceSyncTable<TestDataObject>
T must implement IMobileServiceSyncTable<T>
but it doesn't, because that would be
IMobileServiceSyncTable<IMobileServiceSyncTable<TestDataObject>>
Try this instead:
public async void RefreshLocalListFromLocalStore<T>(IMobileServiceSyncTable<T> table)
{
...
}

Related

Making generic function async fails on type conversion due to using Task<T>

Here is the structure of given interfaces and classes:
public abstract class Entity
{ }
public class Group : Entity
{ }
public interface ICollectionPage<T>
{ }
public interface IGraphServiceGroupsCollectionPage : ICollectionPage<Group>
{ }
And here are two methods, that use these interfaces. One is sync and the other is async, thous using Task<T> for the arguments:
private static Task<IEnumerable<T>> GetAllAsync<T>(Task<ICollectionPage<T>> collectionTask)
where T : Entity
{
throw new NotImplementedException();
}
private static Task<IEnumerable<T>> GetAll<T>(ICollectionPage<T> collectionTask)
where T : Entity
{
throw new NotImplementedException();
}
If we try to use the synchronous method within our code, everything works as expected:
var collectionPage = (IGraphServiceGroupsCollectionPage)null;
var groups = GetAll(collectionPage);
But if we try to use the async method, we got a type conversion error:
var collectionPageTask = (Task<IGraphServiceGroupsCollectionPage>)null;
var groupsFromAsync = GetAllAsync<IGraphServiceGroupsCollectionPage>(collectionPageTask);
error CS1503: Argument 1: cannot convert from 'System.Threading.Tasks.Task<RemotePowershell.IGraphServiceGroupsCollectionPage>' to 'System.Threading.Tasks.Task<RemotePowershell.ICollectionPage<RemotePowershell.IGraphServiceGroupsCollectionPage>>'
Any idea on how we can avoid this error in the async call?
The complete code:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public interface IGraphServiceClient
{
}
public abstract class Entity
{
}
public class Group : Entity
{
}
public interface ICollectionPage<T>
{
}
public interface IGraphServiceGroupsCollectionPage : ICollectionPage<Group>
{
}
public class Program
{
private static Task<IEnumerable<T>> GetAllAsync<T>(Task<ICollectionPage<T>> collectionTask)
where T : Entity
{
throw new NotImplementedException();
}
private static Task<IEnumerable<T>> GetAll<T>(ICollectionPage<T> collectionTask)
where T : Entity
{
throw new NotImplementedException();
}
static void Main(string[] args)
{
var collectionPage = (IGraphServiceGroupsCollectionPage)null;
var groups = GetAll(collectionPage);
var collectionPageTask = (Task<IGraphServiceGroupsCollectionPage>)null;
var groupsFromAsync = GetAllAsync<IGraphServiceGroupsCollectionPage>(collectionPageTask);
}
}
Update due to: Why do you want to do this?
The reason is quite simple. In the first step, we'd like to write an extension method to another async method. This method has the following signature:
public interface IGraphServiceUsersCollectionRequest
{
public Task<IGraphServiceGroupsCollectionPage> GetAsync();
}
And when we like to call it we like to do it this way:
var request = (IGraphServiceUsersCollectionRequest)null;
var result = await request.GetAsync().GetAllAsync();
And to get this to work, we need an extension method that takes an Task<IGraphServiceGroupsCollectionPage> as input and returns an Task<IEnumerable<Group>>. By trying to build this extension method we ran into the above problems and we boild it down to the above given example.
You will need to make the Task parameter more generic.
private static Task<IEnumerable<T>> GetAllAsync<T,T2>(Task<T> collectionTask)
where T : ICollectionPage<T2>
where T2 : Entity
{
throw new NotImplementedException();
}
...
var collectionPageTask = (Task<IGraphServiceGroupsCollectionPage>)null;
var groupsFromAsync = GetAllAsync<IGraphServiceGroupsCollectionPage,Entity>(collectionPageTask);
The problem is that Task<T> (being a class) is invariant. From the comments in the question:
IGraphServiceGroupsCollectionPage implements ICollectionPage<Group> and the method works on Task<ICollectionPage<T>>.
You're expecting a Task<IGraphServiceGroupsCollectionPage> to be compatible with Task<ICollectionPage<Group>>. It isn't. You can tell that very simply:
Task<IGraphServiceGroupsCollectionPage> task1 = null;
Task<ICollectionPage<Group>> task2 = task1;
This gives an error of:
Error: Cannot implicitly convert type 'System.Threading.Tasks.Task<IGraphServiceGroupsCollectionPage>' to 'System.Threading.Tasks.Task<ICollectionPage<Group>>'
Additionally, this call:
GetAllAsync<IGraphServiceGroupsCollectionPage>(collectionPageTask)
... is providing an explicit type argument of IGraphServiceGroupsCollectionPage for T, and the parameter is of type ICollectionPage<T>, so the compiler is trying to convert the argument to an Task<ICollectionPage<IGraphServiceGroupsCollectionPage>>.
Michael Randall has shown the solution to this, making the call generic in two type parameters instead of one..

Generic Method Constraint of child class issue

First here's the break down of the class hierarchy:
public class Entity {
}
public abstract class AuditBase<T> {
protected abstract void SomeMethod();
}
public class EntityAudit : AuditBase<Entity> {
protected override void SomeMethod() {
}
}
Then, I have a method with a constraint like so:
public async Task<IEnumerable<T>> Query<T>(int id) where T : AuditBase<T>
{
var instance = Activator.CreateInstance<T>();
var refTable = instance.RefTable;
var collection = _context.Database.GetCollection<T>("Audit");
var filter = String.Join("{ RefTable: '", refTable, "', Object: { Id: {'$eq': ", id.ToString(), "} } }");
return await collection.FindSync<T>(filter).ToListAsync();
}
However, I get an error when I use the following code:
var result = await Query<EntityAudit>(5);
The error is:
The type 'EntityAudit' cannot be used as type parameter 'T' in the generic type of method 'Audit.Query<T>(int)'. There is no implicit reference conversion from 'EntityAudit' to 'AuditBase<EntityAudit>'.
I kind of understand the issue. My goal is really to restrict the returned IEnumerable to only contain objects that are children of AuditBase. Currently, it's trying to return items of type 'Entity' due to T.
I can't do the constraint as so: ... where T: Audit as Audit "requires one parameter."
Any thoughts? How do I implement the constraint?
EDIT:
So I ended up doing the following:
public async Task<IEnumerable<T>> Query<T,U>(int id) where T: AuditBase<U>
{
...
}
var result = await Query<EntityAudit, Entity>(5)
This works.
But, is there a better way?
create a non generic audit base base class
//...
public abstract class AuditBase {
//...
}
public abstract class AuditBase<T> : AuditBase {
protected abstract void SomeMethod();
}
//...
and use that for the constraint
public async Task<IEnumerable<T>> Query<T>(int id) where T : AuditBase {
//...
}

How to pass type dynamically to Activator.CreateInstance(object)?

I am trying to implement generic solution using Activator.CreateInstace()
Below I have interface,
public interface INewReleaseValidationRule<T> where T : INewReleaseValidationEntity
{
void Run(CtxNewRelease ctx, IEnumerable<T> entities);
string GetMessage(string messageName, string fallbackMessage);
}
public interface INewReleaseValidationEntity
{}
My class CustomerAssociation is:
public class CustomerAssociation : INewReleaseValidationEntity
{
public void Run(Context.Ctx context, IList<INewReleaseValidationEntity> entitiesObject)
{}
}
Then I have view model which is also implementing INewReleaseValidationEntity.
public class ForecastViewModel : INewReleaseValidationEntity
{
}
Then,
public partial class ValidationRule
{
public void Run(Ctx context, List<ForecastViewModel > entity)
{
var validation = this.GetExecutionType();
var execution = (INewReleaseValidationRule<entity>)Activator.CreateInstance(validation);
execution.Run(context, entity.ToArray());
}
}
In above highlighted statement I am getting error.
If I use,
var execution = (CustomerAssociation)Activator.CreateInstance(validation);
then it works perfectly fine. But I want to provide the explicit type (in this case CustomerAssociation) dynamically.
All my explicit type (that is CustomerAssociation) and others will be inherited from INewReleaseValidationRule<T>.
If I write
var execution = (INewReleaseValidationRule<ForecastViewModel>)Activator.CreateInstance(validation);
then getting runtime error,
Unable to cast object of type 'CustomerAssociation' to type 'INewReleaseValidationRule`1[ForecastEstimateViewModel]'.
It's a bit unclear from the code what the actual intent is, but you can try adjusting your validator's run method to take a generic type like this:
public partial class ValidationRule
{
public void Run<T>(Ctx context, List<ForecastViewModel> entity)
where T : class, INewReleaseValidationEntity
{
var execution = (T)Activator.CreateInstance<T>();
execution.Run(context, entity.ToArray());
}
}
And call it like this:
new ValidationRule().Run<CustomerAssociation(context, entities);

Specify generic type as argument param without knowing T

I'm approaching a problem while still having some ignorance regarding Generics and their proper declarations / uses. I get the premiss, but some of the ins-n-outs of generics still elude me.
Given the following code (does not compile and contains code-smell):
public interface IUIConcern<out T> where T : IUIConcernExtension
{
string Name { get; }
Func<T> Extend();
}
public class UIConcern
{
public static void Register<T>(string concernName, IUIConcern<T> uiConcern) where T : IUIConcernExtension
{
Concerns.Add(uiConcern);
}
public static List<IUIConcern<T>> Concerns{
get {
// Logic...
}
set {
// Logic...
}
}
}
... I have a few questions:
Why do I have to specify this part public static void Register<T>(string concernName, IUIConcern<T> uiConcern) where T : IUIConcernExtension
with a constraint when I have already constrained the T in the declaration public interface IUIConcern<out T> where T : IUIConcernExtension
How can I have a property that holds a List<> of my IUIConcern<T> without knowing T other than knowing it will be derived from IUIConcernExtension?
Again, I realize this doesn't compile and is not correct, just looking to see how I can hold a list of generic items that may have many different type of IUIConcern<> elements.
Thank you!
You need to have a base interface, for instance:
public interface IUIConcern
{
string Name { get; }
}
public interface IUIConcern<out T> : IUIConcern where T : IUIConcernExtension
{
Func<T> Extern();
}
How you would define Concerns and Register would depend on how you treat T. Alternatively if you only deal with instances where you know T, you could use a Dictionary<Type, List<IUIConcern>> to hold anything, or potentially drop the base interface and just store using object depending on what you need in your controller code.
The problem is not located at the interface, but the problem is because of your generic implementation using static methods and properties.
The answer from Guvante was correct when saying that you need to define the IUIConcernExtension, but that is of course very logical, so im assuming you have just omitted that part since it does not matter for the issue you are facing.
The problem in the code is that you have created a class that has static methods and procedures, with the generic definition not laying at class level, but at methods level, because of this, the property that has and the Method cannot assume you are always with the same type!!
Lets say you call call :
Register<string>("something", UIConcern<string>)
but before that you have already called:
Register<Type>("something", UIConcern<Type>)
How could the compiler allows you to that?! So the answer is to define the generic type at class level, with this all properties and methods will be of same .
Also you need to use a private member for your list, since you doing everything static, the correct code should be:
interface IUIConcernExtension
{
string Name { get; }
}
public interface IUIConcern<out T> where T : IUIConcernExtension
{
Func<T> Extend();
}
public class UIConcern<T> where T : IUIConcernExtension
{
private static List<IUIConcern<T>> _Concerns = new List<IUIConcern<T>>();
public static void Register(string concernName, IUIConcern<T> uiConcern)
{
Concerns.Add(uiConcern);
}
public static List<IUIConcern<T>> Concerns
{
get { return _Concerns; }
set { _Concerns = value; }
}
}

Simple repository for .Net 2.0

I am trying to use the repository pattern for a site made in .Net 2.0. All client code is expecting datatable for binding and I am not going to be able to change that, so please bear with me.
I am having a (probably dumb) issue. I cannot figure out how to pass a strongly typed entity to my concrete repository. The interface is forcing me to pass an Employee type but I need to pass a Developer type (it derives from Employee) because it has specific properties not found in the base class.
public interface IEmployeesRepository
{
DataTable Employees { get; }
void SaveEmployee(Employee employee);
void DeleteEmployee(Employee employee);
}
public class DevelopersRepository : IEmployeesRepository
{
public void SaveEmployee(Developer employee)
{
Database db = new SqlDatabase(connectionString);
DbCommand dbCommand = db.GetStoredProcCommand("Developers_Insert", employee.ProgrammingLanguage);
db.ExecuteNonQuery(dbCommand);
}
}
}
I tried using generics instead but then I still will not have a strongly typed object right?
I could be wrong but it sounds like you want to use a generic constraint:
public interface IEmployeeRepository<T>
where T : Employee
{
DataTable Employees { get; }
void SaveEmployee(T employee);
void DeleteEmployee(T employee);
}
public class DevelopersRepository : IEmployeeRepository<Developer>
{
public void SaveEmployee(Developer employee)
{
Database db = new SqlDatabase(connectionString);
DbCommand dbCommand = db.GetStoredProcCommand("Developers_Insert", employee.ProgrammingLanguage);
db.ExecuteNonQuery(dbCommand);
}
}
DevelopersRepository implements IEmployeesRepository so it must implement all methods in the interface.
public void SaveEmployee(Employee employee)
{
if (!(employee is Developer)) throw new Exception("...");
...
}

Categories

Resources