Given classes and interfaces below, I am wondering why implicit cast:
ISomeModelAbstract<IBasicModel> x = new ConcreteClass();
Is impossible. I tried
public interface ISomeModelAbstract<out T> where T: IBasicModel
But then I cannot use GetById and GetAll method. I appreciate any help or hint. Thank you.
public interface IBasicModel {
string _id { get; set; }
}
public class SomeModel: IBasicModel {
public string _id { get; set; }
/* some other properties! */
}
public interface ISomeModelAbstract<T> where T: IBasicModel
{
bool Save(T model);
T GetById(string id);
IEnumerable<T> GetAll();
bool Update(string id, T model);
bool Delete(string id);
}
public abstract class SomeModelAbstract<T> : ISomeModelAbstract<T> where T : IBasicModel
{
public bool Save(T model)
{
throw new System.NotImplementedException();
}
public T GetById(string id)
{
throw new System.NotImplementedException();
}
public IEnumerable<T> GetAll()
{
throw new System.NotImplementedException();
}
public bool Update(string id, T model)
{
throw new System.NotImplementedException();
}
public bool Delete(string id)
{
throw new System.NotImplementedException();
}
}
public interface IConcreteClass: ISomeModelAbstract<SomeModel> { }
public class ConcreteClass: SomeModelAbstract<SomeModel>, IConcreteClass { }
This doesn't work because of Covariance concern. Consider this sample code.
public class SomeModel2: IBasicModel {
public string _id { get; set; }
/* some other properties! */
}
After that, you can pass for example some object of SomeModel2 to Save method of x and obviously, this is not OK.
ISomeModelAbstract<IBasicModel> x = new ConcreteClass();
var m = new SomeModel2();
x.Save(m);
To preventing this you should tell implicitly that you use your generic type only in return (out) places, not in inputs. For example:
public interface ISomeModelAbstract<out T> where T: IBasicModel
And after doing this, unfortunately, you can't use Save and Update method in your ISomeModelAbstract interface. Because they use T in parameter (input) place.
For more information please see link below: http://tomasp.net/blog/variance-explained.aspx/
Another answer already describes the reason why it doesn't work in current state. I want to add that in such cases it's often useful to extract covariant or contravariant parts of your interface (or both) into separate interface(s). For example:
// covariant part, T is used only as return value
// ISomeModelRead is not the best name of course
public interface ISomeModelRead<out T> where T : IBasicModel {
T GetById(string id);
IEnumerable<T> GetAll();
}
// the rest of interface, also implementing covariant part
public interface ISomeModelAbstract<T> : ISomeModelRead<T> where T : IBasicModel {
bool Save(T model);
bool Update(string id, T model);
bool Delete(string id);
}
Now everything works the same, except you can do:
ISomeModelRead<IBasicModel> x = new ConcreteClass();
x.GetAll();
x.GetById("id");
Related
I have some problem with delegates
My scheme of classes:
public interface IWorker<T> where T : IModel
{
T Do(T model);
T ReadyToWork(T model);
}
public abstract class Workers<T> : IWorker<T> where T : IModel
{
public abstract T Do(T model);
public abstract T ReadyToWork(T model);
}
Class to work! FirstModel : IModel
public class FirstWorker : Workers<ModelFirst>
{
public override ModelFirst Do(ModelFirst model)
{
return new ModelUserFirst();
}
public override ModelFirst ReadyToWork(ModelFirst model)
{
throw new NotImplementedException();
}
}
I can create many work specials classes, and to work with them I created one access point:
public class WorkPoint<T> where T : IModel
{
public static Func<T, T> Do { get; set; }
public static Func<T, T> ReadyToWork{ get; set; }
public WorkPoint(ModelFirst mod)
{
Do = FirstWorker.Instance().Do;
ReadyToWork= FirstWorker.Instance().ReadyToWork;
}
}
ok, and question. on moment assignments Do and ReadyToWork I catching error
Error CS0123 No overload for 'Do' matches delegate 'Func'
Whats wrong?
It's not the most elegant solution, but this works:
public class WorkPoint<T> where T : IModel
{
public Func<T, T> Do { get; }
public Func<T, T> ReadyToWork { get; }
protected WorkPoint(Func<T, T> f, Func<T, T> r)
{
Do = f;
ReadyToWork = r;
}
}
// Create a simple class like this for evert worker type you need
public class FirstWorkPoint : WorkPoint<ModelFirst>
{
private FirstWorkPoint() :
base(FirstWorker.Instance().Do, FirstWorker.Instance().ReadyToWork)
{ }
// Public method to get a new base instance
public static WorkPoint<ModelFirst> New() => new FirstWorkPoint();
}
This will add a bit of overhead due to the additional class created, but it should act as a workaround for that covariance issue being pointed out in the comments.
This way you could just do:
WorkPoint<ModelFirst> point = FirstWorkPoint.New();
Edit: Also, if you don't need that base Workers<T> class I'd say you could just get rid of it and have the actual worker classes directly inherit from your interface. After all, the base class doesn't provide any additional functionalities in the above code.
I have an interface to define my records\models
public interface IStockItem
{
string Code { get; set; }
string Description { get; set; }
decimal FreeStock { get; set; }
}
Is it best to put the actions into another interface?
public interface IStockExport
{
IEnumerable<IStockItem> GetAll();
IEnumerable<IStockItem> GetStockByCode(string code);
decimal GetFreeStock(string code);
}
public interface IStockImport
{
void CreateItem<IStockItem>;
}
Is there a better way to do this and make it more generic? so i can share the actions interfaces with other records\models?
The other records\models are SalesOrder, Customer, Address.
The overall idea is an Import\Export program, that will create\export sales orders in a number of different accounts packages via an API.
This is a common pattern, called the Repository Pattern.
If you want to go down this route, you should create a base interface, Repository<T>, for example:
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
IEnumerable<T> SearchFor(Func<T, bool> predicate);
IEnumerable<T> GetAll();
T GetById(int id);
}
You would make your IStockItem implement an IEntity interface so that it can provide an ID for GetById(), for example:
public interface IEntity
{
int ID { get; }
}
Then you would implement the repository for a data type such as StockItem by declaring the implementing class. It might start a bit like this:
public class Repository<T> : IRepository<T> where T : class, IEntity
{
protected Table<T> DataTable;
public Repository(DataContext dataContext)
{
DataTable = dataContext.GetTable<T>();
}
...
Your code that wanted to get at a repository for a stock item might look like this:
using (var dataContext = new StockItemDataContext())
{
var StockItemRepository = new Repository<IStockItem>(dataContext);
...
This may be overkill for what you want, but it is the general approach.
For full details see this excellent blog post.
Also see this example.
Here's how you might start implementing this pattern for your case:
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
IEnumerable<T> SearchFor(Func<T, bool> predicate);
IEnumerable<T> GetAll();
T GetByCode(string code);
}
public interface IStockItem: IEntity
{
string Description { get; set; }
decimal FreeStock { get; set; }
}
public sealed class StockItem: IStockItem
{
public string Code { get; set; }
public string Description { get; set; }
public decimal FreeStock { get; set; }
}
public interface IEntity
{
string Code { get; }
}
public sealed class MyLowLevelDataAccess
{
public StockItem FindStockItem(string code)
{
return null; // Call your API here.
}
public void DeleteStockItem(string code)
{
// Call your API here.
}
public void InsertStockItem(StockItem item)
{
// Call your API here.
}
public IEnumerable<StockItem> FindAllItems()
{
return FindItemsMatching(x => true);
}
public IEnumerable<StockItem> FindItemsMatching(Func<StockItem, bool> predicate)
{
return null; // Call your API here and return all items matching the predicate.
}
}
public sealed class StockRepository: IRepository<StockItem>
{
private readonly MyLowLevelDataAccess _dataAccess;
public StockRepository(MyLowLevelDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public void Insert(StockItem entity)
{
_dataAccess.InsertStockItem(entity);
}
public void Delete(StockItem entity)
{
_dataAccess.DeleteStockItem(entity.Code);
}
public IEnumerable<StockItem> SearchFor(Func<StockItem, bool> predicate)
{
return _dataAccess.FindItemsMatching(predicate);
}
public IEnumerable<StockItem> GetAll()
{
return _dataAccess.FindAllItems();
}
public StockItem GetByCode(string code)
{
return _dataAccess.FindStockItem(code);
}
}
you can use a generic interface as well:
public interface IRecordExport<T> where T : IRecordBase
{
IEnumerable<T> GetAll();
IEnumerable<T> GetOneByCode(string code);
decimal GetFree(string code);
}
public interface IRecordImport<T> where T : IRecordBase
{
void CreateItem<T>();
}
You could, but it may not be necessary. Interfaces for method-based classes are best used where you want to have polymorphism related to implementation.
In your case, it seems that what you want is to be able to share common functionality (based on the IStockExport interface) but also provide a polymorphic creation mechanism (based on IStockImport).
I would suggest that you implement an abstract base class for IStockExport which can be inherited for all the various types of IStockItem (due to common interface) and then the derived classes should implement IStockExport as each Create<IStockItem>() implementation will be different but can be used in the same way due to common behaviour (always returns IStockItem object).
Given the following
public class Service<T> : IService<T>
{
Repository<T> _repository = new Repository<T>();
public T Get<T>(int id)
{
return _repository.Get<T>(id);
}
}
public interface IService<T>
{
T Get<T>(int id);
}
I get the following warning
Type parameter 'T' has the same name
as the type parameter from outer type
'Services.IService'
I am not sure what the issue is with this, why does it care if my return type is the same as the type I am telling the class to be. Am I missing something here?
You can leave out the <T> in the declaration of Get methods. You are not introducing a new Type Parameter for the Get method which <T> says. The fact that you return a T is enough.
I think this will work:
public class Service<T> : IService<T>
{
Repository<T> _repository = new Repository<T>();
public T Get(int id)
{
return _repository.Get(id);
}
}
public interface IService<T>
{
T Get(int id);
}
You can create a generic method in both generic and non-generic classes.
public class Foo
{
public T Get<T>(int a)
{
}
}
You could also do this in a generic class, but over a different type.
public class Foo<T>
{
public S Get<S>(int a)
{
}
}
You'd want this instead:
public class Service<T> : IService<T>
{
Repository<T> _repository = new Repository<T>();
public T Get(int id)
{
return _repository.Get<T>(id);
}
}
public interface IService<T>
{
T Get(int id);
}
Basically in you're code you're trying to define Get<T>(). When you put that generic definition, you're saying it's specific to that method, not the whole class.
Using the release version of Visual Studio 2010 I think there's a difference in the "Implement Interface" expansion from VS2008
If I speicify an interface and implement it in a class as so:
public interface IRepository<T> where T : IModel
{
T Get<T>(int id);
void Update<T>(T item);
int Add<T>(T item);
}
public class MockRepository : IRepository<MockUser>
{
// ...
}
Then use the "Implement Interface" expansion and get this:
public class MockRepository : IRepository<MockUser>
{
public T Get<T>(int id)
{
throw new NotImplementedException();
}
public void Update<T>(T item)
{
throw new NotImplementedException();
}
public int Add<T>(T item)
{
throw new NotImplementedException();
}
}
Instead of what I expected
public class MockRepository : IRepository<MockUser>
{
public MockUser Get<MockUser>(int id)
{
throw new NotImplementedException();
}
public void Update<MockUser>(MockUser item)
{
throw new NotImplementedException();
}
public int Add<MockUser>(MockUser item)
{
throw new NotImplementedException();
}
}
The IDE uses the type variable name from the generic interface definition T instead of the specified concrete type MockUser.
Is this a bug? Or is something new just for VS2010 / .Net 4.0?
Update:
This is NOT a bug, I didn't specify the interface as I inteded, it should be defined as:
public interface IRepository<T> where T : IModel
{
T Get(int id);
void Update(T item);
int Add(T item);
}
in other words I didn't need to specify the Type parameter T at the interface and method level, but only at the interface.
There's no purpose to <T> as a type parameter to the interface's methods. It's not necessary, and if you remove it, you'll get the expected behavior -- except that the result is this:
public class MockRepository : IRepository<IModel>
{
public IModel Get(int id)
{
throw new NotImplementedException();
}
public void Update()
{
throw new NotImplementedException();
}
public int Add(IModel item)
{
throw new NotImplementedException();
}
}
Generic method type parameters are distinct from interface/class type parameters -- I wouldn't expect them to be implemented using IModel in your example. (In other words, the T in IRepository<T> is not the T in Get<T>.)
It's doing exactly the right thing for you.
Each of the methods of your interface has its own T parameter, which is still unspecified until the caller of the method eventually specifies it. Your interface's T is unused.
I thought I'd use some (what I thought was) simple generics to enforce CRUD on some Business Classes.
eg.
public interface IReadable <T>
{
T Read<T>(string ID);
}
and then perhaps, I could have a NoteAdapter to do CRUD with the Note class eg.
public class NoteAdapter : IReadable<Note>
{
public Note Read<Note>(string ID) {
return new Note();
}
}
But for some reason, te compiler is getting confused if I have both a generic return Type and a function Parameterized with the same generic Type. That is , if I do :
public interface IReadable <T>
{
void Read<T>(string ID);
}
public class NoteAdapter : IReadable<Note>
{
public void Read<Note>(string ID) {
return new Note();
}
}
It compiles fine, although it doesnt do what I want it to !
Also, this :
public interface IReadable <T>
{
T Read (string ID);
}
public class NoteAdapter : IReadable<Note>
{
public Note Read(string ID) {
return new Note();
}
}
works fine as well, Although it too does not satisfy the requirements ! -- Why ?
Because then I can't have one Class that implements a bunch of these Interfaces ..eg.
public interface IReadable <T>{
T Read (string ID);
}
public class UniversalAdapter : IReadable<Note>, IReadable<Customer> ...
{
public Note Read(string ID) {
return new Note();
}
public Customer Read(string ID) {
return new Customer();
}
}
Coz this would not compile as return types are not part of the methods signature !
I was under the impression, in C# 3.5 +
T Foo(T t);
T Foo<T> (T t);
T Foo(<SomeType> someInstance);
All have different signatures! What am I missing here ?
You've overspecified the interface. You declare T in the interface definition, but then you redeclare it in the method's definition:
public interface IReadable <T> /* T is declared here */
{
T Read<T>(string ID); /* here, you've declare a NEW generic type parameter */
/* that makes this T not the same as the T in IReadable */
}
Due to this confusion, you end up with an error when you try to implement the interface.
public class NoteAdapter : IReadable<Note> /* IReadable defines T to be Note */
{
public Note Read<Note>(string ID) { /* Here, you're declaring a generic parameter */
/* named Note. This name then conflicts with */
/* the existing type name Note */
return new Note();
}
}
To fix this, you simply need to remove the generic parameter from the Read function, both in the interface, and in the NoteAdapter class:
public interface IReadable <T>
{
T Read(string ID);
}
public class NoteAdapter : IReadable<Note>
{
public Note Read(string ID) {
return new Note();
}
}
EDIT:
Okay, I read the rest of your post, and it seems that you've already discovered that this "works", but you seem to think it's incorrect. Why? What requirements does this not meet?
public interface IReadable <T>
{
T Read<T>(string ID);
}
here really two different Ts : IReadable <T> and T Read<T>(string ID)
maybe just
public interface IReadable <T>
{
T Read(string ID);
} ?
because otherwise is equal to
public interface IReadable <T>
{
X Read<X>(string ID);
}
Good Generics tutorial
EDIT:
May be you need public interface IReadable <T> { T Read(T ID); } ?
The CIL does not support method overloading by return type.