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!

+2


source to share


6 answers


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 (therefore IList<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.

+6


source


How about AreProductsAvailable(IEnumerable<IProduct> products)

?

Name it like this:



using System.Linq;

List<ProductTypeA> products = ...;
AreProductsAvailable(products.Cast<IProduct>());

      

+3


source


public bool AreProductsAvailable<T>

( <T>

), T: IProduct {...} >


0


source


I know this part doesn't answer your question, but you can use interfaces.

The finger for using the interfaces is:

If B is your class and it is A, A should be an interface. If B is your class and it is A, A must be the base class.
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.
0


source


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).

0


source


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.

0


source







All Articles