With C # 3.0, how do I write code based on a shared collection interface?
I want to write code that is decoupling and clean, and I know that by programming the interface instead of implementing it, my code will be more flexible and extensible. So instead of writing methods like:
bool IsProductAvailable(ProductTypeA product);
I write methods like:
bool IsProductAvailable(IProduct product);
While my products are implementing IProduct:
class ProductTypeA : IProduct
I should be fine. It's okay until I start using shared collections. Since C # 3.0 does not support covariant and contravariant, although both ProuctTypeA and ProductTypeB implement IProduct, you cannot put a List into a List. This is quite troublesome because many times I want to write something like:
bool AreProductsAvailable(List<IProduct> products);
So that I can check the availability of the product by writing:
List<ProductA> productsArrived = GetDataFromDataabase();
bool result = AreProductsAvailable(productsArrived);
And I only want to write one AreProductsAvailable () method that works on all IProduct collections.
I know that C # 4.0 will support covariant and contravariant, but I also understand that there are other libraries that seem to have been resolved. For example, I was trying to use ILOG Gantt to manipulate a gantt chart and found that they have many collectible intefaces that look like this:
IActivityCollection
ILinkCollection
So it seems like their approach is to update the shared collection with an interface. So instead of "bool AreProductsAvailable", I can do:
bool AreProductsAvailable(IProductCollection products);
And then write some code to have the IProductCollection accept all general IProduct collections, be it List or List.
However, I don't know how to write an IProductCollection interface that does this "magic" .: - <(shame) ....
Could someone shed some light on me? I had been pushed for so long and I was so eager to do the "right thing". Oh, thanks!
source to share
Even with .NET 4.0 List<T>
won't be an option for two reasons:
- It is a class, not an interface or delegate
- It uses in
T
both input and output position (thereforeIList<T>
not an option either in .NET 4.0)
One of the common solutions to this problem is to add another type parameter:
bool AreProductsAvailable<T>(IList<T> products) where T : IProduct
You can then iterate over the list, accessing each item only as IProduct
, but the caller can use any type of compatible list.
source to share
I know this part doesn't answer your question, but you can use interfaces.
The finger for using the interfaces is:
Examples of possible interfaces for your design:
I Serializeable, I am Tradeable, I am Shippable
Examples of possible classes / base classes for your design:
Product, client
This part might answer your question:
Use ICollection <Product> or IEnumerable <Product> (or IProduct / ProductBase).
Collections like List <gt ;, ObservableCollection <gt ;, Dictionary <,> implement these interfaces, and you can easily define a new collection that implements them.
Then your code would be:
bool AreProductsAvailable (ICollection <IProduct> products)
{
foreach (var product in products)
if (product.IsAvailable) ...
}
Just make sure that all your GetProducts () methods return a base type / interface collection.
source to share
I am stuck with the same issue. I had
class Bar : IFin // IFin is interface
{
}
Passing a list to a function that expected List to be a headache (I can't figure out why ... Bar implements everything in IFin !!).
I ended up using List <>. ConvertAll with conversion function as below:
public static IFin ToIFin(Bar_bar)
{
return (IFin)_bar;
}
I know I sometimes miss very obvious things, but he jumps towards me, even though the hoop looked silly. I know this is not graceful and it generates the full IFin list again, but at least the new list still contains my original Bar objects (which I checked).
source to share
I probably would not approach the problem in this way (although I understand that this could be an example and not a real scenario ...)
When using an interface, the consumer does not have to worry about the specific implementation of the interface. This abstraction is fully used for using interfaces.
Since the called code needs to know what type of product it is being requested for, it needs to know the interface developer. Since the reason for using an interface is to hide this knowledge, this is a pretty good indication that you shouldn't be using interfaces in this case.
The best idea might be a transmission ProductId
or something similar. Now you can include a method in your interface GetProductId()
. But if the interlocutor really wants ProductId
, he is more untethered to just give him what he wants, rather than what he can use to get what he really wants.
source to share