I have a method which takes a certain generic object, which basically orders these objects based on a list of tags. Because I want to use this method for multiple objects, I have created a class which only contains the Id, list of tags and an average rating from each object, it looks like this:
public class RecommenderContentItem
{
public Guid Id { get; set; }
public List<Tag> Tags { get; set; } //A tag is an object which only contains an Id and value, not relevant to the question.
public double AverageRating { get; set; }
}
Now I have tried to create a generic method which takes T and checks which type it is, before converting it. The possible objects it can filter are Restaurant
, AlgorithmRestaurant
and Dish
. All of these classes contain an Id, list of tags and an average. It looks like this:
public static List<Guid> FilterOnContent<T>(List<T> ratedItems,
List<T> itemsToFilter)
{
var cnv = new RciConverter();
var ratedRcis = new List<RecommenderContentItem>();
var toFilterRcis = new List<RecommenderContentItem>();
if (typeof(T) == typeof(Restaurant))
{
var rated = (IEnumerable<Restaurant>)ratedItems;
var toFilter = (IEnumerable<Restaurant>)itemsToFilter;
ratedRcis = cnv.ConvertMany(rated).ToList();
toFilterRcis = cnv.ConvertMany(toFilter).ToList();
}
if (typeof(T) == typeof(AlgorithmRestaurant))
{
var rated = (IEnumerable<AlgorithmRestaurant>)ratedItems;
var toFilter = (IEnumerable<AlgorithmRestaurant>)itemsToFilter;
ratedRcis = cnv.ConvertMany(rated).ToList();
toFilterRcis = cnv.ConvertMany(toFilter).ToList();
}
if (typeof(T) == typeof(Dish))
{
var rated = (IEnumerable<Dish>)ratedItems;
var toFilter = (IEnumerable<Dish>)itemsToFilter;
ratedRcis = cnv.ConvertMany(rated).ToList();
toFilterRcis = cnv.ConvertMany(toFilter).ToList();
}
if (!ratedRcis.Any() || !toFilterRcis.Any())
throw new TypeArgumentException("Invalid type."); //Custom exception written by Jon Skeet.
return ContentBasedFilter.Filter(ratedRcis, toFilterRcis).Select(rci => rci.Id).ToList();
}
The converter class above has an interface, and converts (or maps) the object to an RecommenderContentItem
. It looks like this:
public class RciConverter : IConverter<Restaurant, RecommenderContentItem>,
IConverter<AlgorithmRestaurant, RecommenderContentItem>,
IConverter<Dish, RecommenderContentItem>
{
//For each method, I have to call ToList() on the tag list, since they're ICollections
public IEnumerable<RecommenderContentItem> ConvertMany(IEnumerable<AlgorithmRestaurant> sourceObjects)
{
return sourceObjects.Select(rest => new RecommenderContentItem
{
Id = rest.RestaurantId,
AverageRating = rest.AverageRating,
Tags = rest.Tags.ToList()
});
}
public RecommenderContentItem Convert(AlgorithmRestaurant sourceObject)
{
return new RecommenderContentItem
{
Id = sourceObject.RestaurantId,
AverageRating = sourceObject.AverageRating,
Tags = sourceObject.Tags.ToList()
};
}
public IEnumerable<RecommenderContentItem> ConvertMany(IEnumerable<Dish> sourceObjects)
{
return sourceObjects.Select(dish => new RecommenderContentItem
{
Id = dish.Id,
AverageRating = dish.AverageRating,
Tags = dish.Tags.ToList()
});
}
public RecommenderContentItem Convert(Dish sourceObject)
{
return new RecommenderContentItem
{
Id = sourceObject.Id,
AverageRating = sourceObject.AverageRating,
Tags = sourceObject.Tags.ToList()
};
}
public IEnumerable<RecommenderContentItem> ConvertMany(IEnumerable<Restaurant> sourceObjects)
{
return sourceObjects.Select(rest => new RecommenderContentItem
{
Id = rest.Id,
AverageRating = rest.AverageRating,
Tags = rest.Tags.ToList()
});
}
public RecommenderContentItem Convert(Restaurant sourceObject)
{
return new RecommenderContentItem
{
Id = sourceObject.Id,
AverageRating = sourceObject.AverageRating,
Tags = sourceObject.Tags.ToList()
};
}
}
And the interface:
public interface IConverter<in TSource, out TDestination>
where TSource : class
where TDestination : class
{
IEnumerable<TDestination> ConvertMany(IEnumerable<TSource> sourceObjects);
TDestination Convert(TSource sourceObject);
}
Now my question is, am I doing this the right way? I haven't worked a lot with generics or C# in general, so I'm not sure if there are better ways to achieve what I'm trying to accomplish. If you need more information about classes or functionality, please let me know so I can add it to my post!