Generics or not Generics - c#

Basically I have a custom List class that contains different fruits. Assume that each fruit has an ID number that is stored in the list.
Is it better to have:
new AppleList();
new OrangeList();
new LemonList();
or
new FruitList<Fruit.Apple>();
new FruitList<Fruit.Orange>();
new FruitList<Fruit.Lemon>();
Things to consider:
All IDs are of type int.
The type of the fruit will not affect the implementation of the List itself. It will only be used by the client of the list, like an external method, etc.
I would like to use the one that is clearer, better in design, faster, more efficient, etc. Additionally if these above 2 techniques are not the best, please suggest your ideas.
EDIT: Btw Fruit is an enum if that wasn't clear.

Use a combo:
public class AppleList : FruitList<Apple> { ... }
public class OrangeList : FruitList<Orange> { ... }
public class LemonList : FruitList<Lemon> { ... }
Put the common logic in the base list class:
public class FruitList<T> : List<T>
where T : IFruit
{ ... }

If you use generics, is there a purpose to create the FruitList type? Could you just use List?
There won't be much difference in performance, so I say why create three different classes when one would do the same exactly thing? Use the generic solution.

It's much easier to maintain 1 generic list than 3 non-generic versions. If you really like the AppleList name you can always use the using trick to name a generic list
using AppleList=Fruit.FruitList<Fruit.Apple>

•All IDs are of type int.
•The type of the fruit will not affect the implementation of the List itself. It will only be used by the client of the list, like an external method, etc.
Given these two facts, I wouldn't bother with generics. I would put a normal property on FruitList to indicate which type of fruit it is.

Reuse the generic collection classes and subclass them only if you're adding additional functionality. Keep your subclass implementation generic if you can. This is the least complex implementation.

Use the Generic list, no point in crating 3 lists and it's always good to keep a level of abstraction. (IFruit would be a good interface).

I would not recommend the accepted answer and I think you meant something like this instead:
public enum Fruit
{
Apple,
Orange,
Lemon
}
public interface IFruitList : IList<int>
{
Fruit Type { get; }
};
public class FruitList : List<int>, IFruitList
{
private readonly type;
FruitList(Fruit type)
: base()
{
this.type = type;
}
FruitList(Fruit type, IEnumerable<int> collection)
: base(collection)
{
this.type = type;
}
Fruit Type { return type; }
}

You should assume YAGNI unless you need it. Therefore, if you don't need antyhing more than you get in List, then just List<T>. If for some reason you have to override List, then create
FruitList<T> : List<T> where T : Fruit
If your lists diverge and are no longer polymorphic, then consider implementing your custom lists:
AppleList
OrangeList
LemonList
Try as best you can, however, to keep your inheritance hierarchy as flat as possible to avoid overcomplicating your solution.

Related

How to avoid specifying redundant types when instantiating a generic class

I have a generic interface as defined below (IAmMeasurable). I have an implementation of that interface (Sales). I am trying to create a generic class (Fact) such that I can instantiate it like so:
var todaySales = new Fact<Sales>();
Unfortunately, I am forced to do the following:
var todaySales = new Fact<Sales, decimal>();
Which seems awkward since Sales is defined as IAmMeasurable<decimal>. The decimal is implied in the usage of Sales
public interface IAmMeasurable<TValue> where TValue : struct
{
}
public class Sales : IAmMeasurable<decimal>
{
}
public class Fact<TMeasure, TValue>
where TMeasure : IAmMeasurable<TValue>
where TValue : struct
{
public TValue Observed { get; set; }
}
Perhaps this is just a limitation of the language? Or is there an alternative way to structure this that to achieve my goal? Or am I simply not thinking of the problem properly?
In my mind, there are things that are measurable and they are measured in a specific type (Sales is measured in dollars, represented as a decimal). A fact is an observation of some measure. I observe that today Sales is $100 (100m).
If you want to avoid this, you simply need to design an intermediate class where TValue of Fact is decimal:
public class DecimalFact<TMeasure> : Fact<TMeasure, decimal>
where TMeasure : IAmMeasurable<decimal>
{
}
Even in its 6th version, C# has no generic type parameter inference like it would happen in methods. BTW, it would be hard that a generic type parameter could be infered by usage. How would C# compiler know that IAmMeasurable<T> T generic parameter is TValue? Maybe some new generic constraint like TValue is TMeasure? Who knows ;)
It seems like above solution is the best workaround and it's the most common solution to concretize generic parameters by design.

Cast Collection<Derived> to Collection<Base>

Got another simple question here that is eluding me.
I have 2 classes:
namespace Assets
{
public class BaseAsset
{
// Code here
}
}
And
namespace Assets
{
public class Asset : BaseAsset
{
// Code here
}
}
I have a function that returns a collection of Asset from the database and I want another function to execute that function and return a collection of BaseAsset.
I have tried this:
public static Collection<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
{
return (Collection<BaseAsset>)AssetData.getAssets(CategoryId, UserId, CompanyId);
}
but as you can guess, it doesn't work.
If I was working with lists, I could do:
public static List<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
{
return AssetData.getAssets(CategoryId, UserId, CompanyId).Cast<BaseAsset>().ToList();
}
But I would prefer to use a collection, can anyone come up with an elegant solution?
Cheers,
r3plica
This is a very frequently asked question. The name of the feature that you want is generic covariance; that is, the feature that says "if a giraffe is a kind of animal then a list of giraffes is a kind of list of animals."
The problem is that a list of giraffes is not a kind of list of animals. You can put a tiger into a list of animals, but you can't put a tiger into a list of giraffes, and therefore a list of giraffes cannot be used in any context where a list of animals is expected.
The reason you should use IEnumerable<T> instead of Collection<T> is because as of C# 4, IEnumerable<T> is covariant in T, provided that the type arguments provided are both reference types. That is, a sequence of strings can be used as a sequence of objects, because both are reference types. But a sequence of ints cannot be used as a sequence of objects, because one is a value type.
The reason this is safe is because there is no way to insert a tiger into an IEnumerable<Giraffe>.
If you want the ease of .ToList, just write your own .ToCollection extension method. The implementation should be straightforward - take an IEnumerable<T>, loop through it and add everything into a collection with Add.
The problem is that Collection<T> and ICollection<T> are invariant (that is, Collection<BaseAsset> is neither a subtype nor a supertype of Collection<Asset>).
The problem will be very easily solved by returning either IEnumerable<BaseAsset> or IReadOnlyList<BaseAsset> instead of Collection<BaseAsset>.
That is, you can write:
public static IEnumerable<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
{
return AssetData.getAssets(CategoryId, UserId, CompanyId);
}
The cast becomes unnecessary.
In general, you should prefer interface types (such as IList<T>, IReadOnlyList<T>, ICollection<T> or IEnumerable<T>) over concrete types (Collection<T> or List<T>) when specifying return values and function parameters.
Instead of trying to cast to the base class, why not just extract an interface and use that.
Since the Collection<T> class has a constructor that takes an IList<T> as an argument, you can always do:
Collection<BaseAsset> = new Collection<BaseAsset>(
assetList.Cast<BaseAsset>().ToList());
Of course, if you need to reuse this behaviour, you could make a CastToCollection extension:
public static Collection<TResult> CastToCollection<TResult>(this IEnumerable source)
{
return new Collection<TResult>(source.Cast<TResult>().ToList());
}

Check if objects type inherits an abstract type

Say I have an object, someDrink. It could be of type CocaCola or Pepsi which both inherit the abstract Cola (which inherits Drink) or any kind of drink for that matter. I have a method that returns a string of the most preferred beverage.
public string PreferredDrink(Drink someDrink)
{
var orderOfPreference = new List<Type> {
typeof (Cola),
typeof (PurpleDrank),
typeof (LemonLimeBitters)
...
}
foreach (drinkType in orderOfPreference) {
if (someDrink.GetType() == drinkType) {
return someDrink.ToString()
}
}
throw new Exception("Water will be fine thank you");
}
The code above will not work, because the type of someCola can never be equal to an abstract type. Ideally I would like to do something like:
if (someCola is drinkType) ...
But the is keyword only allows a class name after it.
Is there another way to check if someDrink inherits a given type?
Refactoring isn't totally out of the question if you can suggest a better way to do this.
Sure - you can use Type.IsAssignableFrom:
if (drinkType.IsAssignableFrom(someDrink.GetType()))
Note that it's important that you don't get the target of the call and the argument the wrong way round. I have to consult the docs every time I use it, which is fortunately rarely :)

Implement same Generic Interface 2 times with different Generic parameter

I had to implement 2 interface same time with different generic parameter as below. I get confused enough about it. I had no idea which one of them iterate itself in foreach. Now i understand first one is implicitly choosen.
I have tried new BarList().GetEnumerator() but i can not specify type parameter on method level.
Only solution i have found it that casting it to interface like(new BarList() as IEnumerable<string>)
After confusing about it enough. I just wanted to know that this design is not really good idea ? I have to avoid to implement same generic interface one more time ?
class Program
{
static void Main(string[] args)
{
foreach (var item in new BarList())
{
}
}
}
class BarList: IEnumerable<string>, IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
throw new NotImplementedException();
}
}
Edit:
Let me explain why i am going in this way.
I had to Implement IPagedList<T> interface which is inherited from IList<T>. I wanted to write extension method which convert it to My view model. like below
GetAll().ToPagedList(pageindex);//which is returning IPagedList Then i wanted to use it like below;
GetAll().ToPagedList(pageindex).ToViewModel<T,TViewModel>();
For achieve this I tried to return IPagedList<ViewModel> by that extension method.In that case I have to implement IPagedList 2 times with different parameter. But this strategy made confusing things. This is reason of it.
This seems a bit confusing. Why not make it explicit what is happening by adding the enumerators as properties rather than implementing them on the class. For example,
class ProductCollection
{
public IEnumerable<int> EnumerateTheInts { get { //code to produce enumerator }}
public IEnumerable<string> EnumerateTheStringss { get { //code to produce enumerator }}
}
It isn't always bad to implement an open generic interface twice on an object. For example, IHandle could be implemented by a class which can handle two types of T. However, I would find it confusing to implement IEnumerable twice, because you might not enumerate the type you expect in a for-each or in LINQ. Same reasoning for implementing more than one indexer incidentally. The type of your indexer will determine your result, which I can testify to being extremely confusing!
The compiler is picking the IEnumerator<int> GetEnumerator method by following the rules in 8.8.4 of the C# language specification which first looks for an accessible GetEnumerator() method on the BarList type. The only one of those which is available is the one returning IEnumerator<int>.
If you had made that method use explicit interface implementation as well, then it would have gone onto the later stages of section 8.8.4, which states that if there is more than one type T such that there is an implicit conversion from the expression type (BarList here) to IEnumerable<T> then an error is produced.
I would say this is a confusing design - I would probably add properties or methods to retrieve appropriate "views" on the data.
I'd avoid it. However, it depends on your usage.
It will be okay if you just wanted to pass the instance into a function that expects a IEnumerable<string> parameter explicitely:
you won't have to cast
the function won't even 'see' the other interfaces implemented, so there isn't any confusion.
YMMV
Your current design is confusing. While you have not provided any information about the nature of the collection itself, from the name, I can assume you are supposed to iterate over a bunch of products. Perhaps, you should simply have a class of type Product with a string property and an int property and simply return an IEnumerable<Product> instead.
This way, with LINQ extension methods, you can compose the IEnumerable<T> object you actually mean with:
collection.Select(product => product.IntegerProperty)
collection.Select(product => product.StringProperty)
Of course, you can provide helper methods inside the object as well:
class ProductCollection : IEnumerable<Product> {
public IEnumerable<Product> GetEnumerator() {
// ... return Product objects here.
}
public IEnumerable<int> AsIntegerCollection() {
// yield the integer collection here
}
public IEnumerable<string> AsStringCollection() {
// yield the string collection here
}
}
What are these collections of string and ints? I suppose they mean something in relation with the Product (for example Name, Id, etc...) so I would rather do something like this:
class ProductCollection : IEnumerable<Product>
{
public IEnumerator<Product> GetEnumerator()
{
...
}
public IEnumerator<string> ProductNames // a helper to enumerate product names
{
...
}
public IEnumerator<int> ProductIds // a helper to enumerate product ids
{
...
}
}

Conversion of the type of a Template class?

I have a class named "baseClass".
From this class I inherit a class names "inheritedClass" (public class inheritedClass: baseClass)
The baseClass contains a public function that returns a HashSet<baseClass>. When called from the inheritedClass, the return type is obviously still HashSet<baseClass>, but I need a HashSet<inheritedClass>.
A conversion ala (HashSet<inheritedClass>)returnValue, where returnValue is of Type HashSet<baseClass> doesn't work.
Is there a way to convert the HashSet-Type from baseClass to inheritedClass without converting each element manually?
Thanks in advance,
Frank
Do you really mean C# in the tags? HashMap is a Java type. Also it generally has two type parameters rather than one...
In C#, generic classes are always invariant. Some interfaces will be variant in C# 4, but very few (only those which either only use the type parameter in an output positiion, e.g. IEnumerable<T>, or only use the type parameter in an input position, e.g. IComparable<T>).
If you can provide more precise information about your situation, we'll probably be able to help come up with a simple solution - particularly if you can use LINQ with its Cast<T>() method.
EDIT: Okay, with HashSet<T>:
HashSet<BaseType> baseSet = ...;
var derivedSet = new HashSet<DerivedType>(baseSet.Cast<DerivedType>());
Note that even with C# 4 this would be necessary because the compiler doesn't know that every value in baseSet is an instance of DerivedType - there has to be an execution-time check. The reverse (creating a HashSet<BaseType> from a HashSet<DerivedType>) would work in C# 4.
FURTHER EDIT: If you just want to use UnionWith, that doesn't require a HashSet<DerivedType> - it requires an IEnumerable<DerivedType>. I suggest you do:
HashSet<BaseType> baseSet = ...;
HashSet<DerivedType> derivedSet = ...;
derivedSet.UnionWith(baseSet.Cast<DerivedType>());
Here's the solution
//**Your BaseClass**
public class BaseClass<T> where T : BaseClass<T>
{
public HashSet<T> GetHashSet()
{
HashSet<T> _hSet = new HashSet<T>();
//do some work
//create a HashSet<T> and return;
return _hSet;
}
}
//**Your Inherited/Derived Class**
public class InheritedClass : BaseClass<InheritedClass>
{
//you have the method inherited as you need.}
}

Categories

Resources