How to implement Strategy pattern using Generics in C# - c#

I have a string
string partialCityName
and a generic list .
var city = List<City>
I want to do two things:
1. Filter the list based on the name and I am doing that like this:
var availableCities = cityList.Where(f => f.CityName.StartsWith(partialCityName));
2. Get a list of chars based on the above var "availableCities" and I am doing that like this.
var nextAvailableCharacters = avalibleCities .
Where(s => s.CityName.Length > partialCityName.Length).
Select(s => s.CityName.Substring(partialCityName.Length)[0]).ToList();
Currently this is happening in one method, and is working. However I am trying to understand design patterns, and am trying to implement the Strategy pattern.
So the first question is, is this the correct pattern to use? If so how?
This is what I have got so far.
public interface IFilterStrategy
{
List<T> Filter<T>(List<T> filterThisData, string filter);
}
Then:
public class FilterCityStrategy : IFilterStrategy
{
public List<City> Filter<City>(List<City> filterThisData, string partialCityName)
{
//Fails to compile cityName not member of f
return filterThisData.Where(f => f.CityName.StartsWith(partialCityName));
}
}

Firstly, you declare your interface like this :
public interface IFilterStrategy<T>
{
List<T> Filter(List<T> filterThisData, string filter);
}
And then you need to inherit from a type-specific instantiation of this interface :
public class FilterCityStrategy : IFilterStrategy<City>
{
public List<City> Filter(List<City> filterThisData, string partialCityName)
{
return filterThisData.Where(f => f.CityName.StartsWith(partialCityName)).ToList<City>();
}
}
See https://repl.it/repls/UnluckyEqualRaptors
The error you were getting was because the Filter method was declared as a template method with template parameter City. This means that City acts as an arbitrary type in this function definition and therefore shadows/masks the declaration of your City class elsewhere in your code :
public List<City> Filter***<City>***(List<City> filterThisData, string partialCityName)
{
//Fails to compile cityName not member of f
return filterThisData.Where(f => f.CityName.StartsWith(partialCityName));
}

You could extend it a little bit to accommodate bit more complicated filtering. For example if you have a country filter and a city filter, chances are city filter will have a country code as well.
interface IFilter
{
}
class CountryFilter
{
string PartialCountryName { get; set;}
}
class CityFilter
{
string CountryCode { get; set;}
string PartialCityName { get; set;}
}
interface IFilterStrategy<T,U> where U:IFilter
{
List<T> Filter(List<T> source,U filter);
}
class CountryFilterStategy : IFilterStrategy<Country,CountryFilter>
{
List<Country> Filter(List<Country> source,CountryFilter filter)
{
//logic
}
}
class CityFilterStategy : IFilterStrategy<City,CityFilter>
{
List<City> Filter(List<City> source,CityFilter filter)
{
//logic
}
}

Related

Generic method gives error

I have tried to write a generic method for the below mentioned code snippet.But it gives error on the OrderBy clause ? Could you tell me why ?
var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<StateListDto>>(cache.StringGet(AppConsts.States));
if (values != null) return new ListResultOutput<StateListDto>(values.OrderBy(o => o.Name).ToList());
Generic method :
public ListResultOutput<T> GetCache<T>(string cacheKey)
{
var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
return values != null ? new ListResultOutput<T>(values.ToList().OrderBy(o=>o.Name)) : null;
}
call :
var values = GetCache<StateListDto>(AppConsts.States);
StateListDto.cs
public class StateListDto
{
public string Code { get; set; }
public string Name { get; set; }
}
It gives this error: (click to see the full size image)
If you are expecting to use this for more than just StateListDto I would suggest creating an interface or base class that does have the property called Name then you can guarantee it exists.
Something like:
public interface IDto
{
string Name { get; }
}
and then you can change your method to:
public ListResultOutput<T> GetCache<T>(string cacheKey) where T: IDto
{
var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
return values != null ? new ListResultOutput<T>(values.ToList().OrderBy(o=>o.Name)) : null;
}
You can send the way you want to order by as a parameter like this:
public ListResultOutput<T> GetCache<T>(string cacheKey, Func<T,object> selector)
{
var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
return values != null ? new ListResultOutput<T>(values.OrderBy(selector).ToList()) : null;
}
call :
GetCache<StateListDto>("yourKey", i=>i.Name);
In this way you don't force your class to implement anything - and you can choose to order by other parameter in your code
But all are having Name property.
Then create a common interface for them, something like this:
public interface INamed
{
string Name { get; }
}
And all your models with that property can implement that interface:
public class StateListDto : INamed
Then you can use that interface as a type constraint on the generic method:
public ListResultOutput<T> GetCache<T>(string cacheKey) where T: INamed
That way the compiler can guarantee that the type of T will have a Name property.
Note that a base class, concrete or abstract, can also be used to accomplish this. Though personally I prefer to use interfaces over inheritance unless there's a specific reason to use inheritance.

Trying to Utilise a generic <T> collection

I am using C# and I thought I finally had the chance to understand a Generic type. I have several strongly typed objects that need the same static method. Rather than create one static method for each type I thought I could make it generic. Something I have never done and really wanted too.
Here is where I invoke it.
bool isDuplicate = Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
Here is my static method which resides in a static class called Utilities.
public static bool GetDuplicates<T>(List<T> pBookings)
{
foreach (var item in pBookings)
{
var myVal = item.bookingId
}
return true;
}
So I want to get at the values within var item inside the foreach loop so I can do comparisons. It's definately passed pBookings because I can hover and they have a .Count() with a collection of my strongly typed object. I am missing something here, possibly a casting process. I was wondering if anyone could advise me where I am coming up short.
var myVal = item.bookingId - I cannot get the bookingID from item because I am lacking in some basic understanding here. bookingId doesn't exist, I just get access to extension methods such as .toString and .equals
ANSWER OF SORTS What I did based on all of your really helpful assistance. I utilised Anderson Pimentel. I'm probably still off the mark but wanted to garner anyones thoughts here.
So basically I have several booking models, all need checking for duplicates. I really wanted to understand Generics in this way. So what I did is. Created a base class.
public class BookingBaseModel
{
public int BookingID { get; set; }
public DateTime BookingStartDateTime { get; set; }
public DateTime BookingEndDateTime { get; set; }
}
Then had my booking classes all inherit whats common to all. Like this...
public class RoomBookingModel : BookingBaseModel
{
public string RoomName{ get; set; }
}
public class vehicleBookingModel : BookingBaseModel
{
public string vehicleName{ get; set; }
}
Then in my utilities static helper I did this..
public static void GetDuplicates<T>(List<T> items) where T : BookingBaseModel
{
foreach (var item in items)
{
int myId = item.ID;
DateTime startDateTime = item.BookingStartDateTime;
DateTime endDateTime = item.BookingEndDateTime;
//Do you logic here
}
}
Then finally did something like this in corresponding controller action.
RoomController...
Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
VehicleController....
Utilities.GetDuplicates<VehicleBookingModel>(vehicleBookings);
Is this basically how we go about using generics in this way?
The compiler has no hint of what type is T. If you have a base class (or an Interface) which has the bookingId attribute, like BaseModel, you can constrain the generic type like the following:
public class BaseModel
{
public int Id { get; set; }
}
public static bool GetDuplicates<T>(List<T> items) where T : BaseModel
{
foreach (var item in items)
{
var myId = item.Id;
//Do you logic here
}
return true;
}
Once you're inside your GetDuplicates method, you have lost all knowledge of the RoomBookingModel type. That's the point of generic methods - they should be able to act on whatever type has been passed in to them, e.g. the logic within them should be generic across any type.
So your foreach loop is fine - you know you've been given a list of something, and you know lists can be iterated. But inside that foreach, item is just a T. You don't know what actual type it is because any type could have been passed in. So it doesn't make sense to access a specific property or method off of item - for example, what if I called GetDuplicates passing in a List<int>? It wouldn't have a bookingId property.
As written by others, you don't know anything of T. A classical solution, used by LINQ (see for example GroupBy) is to have your method receive a delegate that does the key-extraction, like:
public static bool GetDuplicates<T, TKey>(List<T> pBookings, Func<T, TKey> selector)
{
foreach (var item in pBookings)
{
TKey key = selector(item);
}
return true;
}
You then use it like:
GetDuplicates(pBookings, p => p.bookingId);
If you like to use a generic method, you have to provide also a generic method, which is able to generate a key out of the specified type T. Luckily we have LINQ which already provides the needed parts to build your generic method:
internal class Extensions
{
public static IEnumerable<T> GetDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return source.GroupBy(keySelector)
.Where(group => group.Skip(1).Any())
.SelectMany(group => group);
}
public static bool ContainsDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return GetDuplicates(source, keySelector).Any();
}
}
By having this (and type inference) you can use these methods e.g. by calling:
var hasDuplicates = roomBookings.ContainsDuplicates(item => item.bookingId);
if(hasDuplicates)
{
Console.WriteLine("Duplicates found:");
foreach (var duplicate in roomBookings.GetDuplicates(item => item.bookingId))
{
Console.WriteLine(duplicate);
}
}
I wonder if generics is really the tool for the job here. Your needs would be better served if each of your strongly typed objects shared a common interface.
"I have several strongly typed objects that need the same static method."
In this situation, all of the classes must share a common feature, such as, for instance, a property BookingId.
So, you'd need to formalize this by extracting this common interface:
public interface IBooking
{
int BookingId{ get; }
}
Make sure that every one of your strongly typed items implements the interface:
public class RoomBooking : IBooking
{
//etc...
}
And now make your static method accept IBooking instances:
public static bool GetDuplicates(IEnumerable<IBooking> pBookings)
{
//does pBookings contain items with duplicate BookingId values?
return pBookings.GroupBy(b => b.BookingId).Any(g => g.Count() > 1);
}
An easy read that isn't obfuscated by the unnecessary use of generics.
Since there are no constraints or hints about what T is, the compiler does not have enough information. Consider
bool isDuplicate = Utilities.GetDuplicates<int>(roomBookings);
Clearly an int does not have a bookingId member.
Every possible specific type for T would have to have a common base class or interface that has a bookingId, and even then you would have to add a generic constraint to your method signature to access that.
Perhaps you are looking for something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Duplicates
{
public static class EnumerableExtensions
{
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter, IEqualityComparer<I> comparer )
{
var hashSet = new HashSet<I>(comparer);
foreach (var item in enumerable)
{
var identity = identityGetter(item);
if (hashSet.Contains(identity)) return true;
hashSet.Add(identity);
}
return false;
}
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter)
{
return enumerable.HasDuplicates(identityGetter, EqualityComparer<I>.Default);
}
}
public class Booking
{
public int BookingId { get; set; }
public string BookingName { get; set; }
}
public class Customer
{
public string CustomerId { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var bookings = new List<Booking>()
{
new Booking { BookingId = 1, BookingName = "Booking 1" },
new Booking { BookingId = 1, BookingName = "Booking 1" }
};
Console.WriteLine("Q: There are duplicate bookings?. A: {0}", bookings.HasDuplicates(x => x.BookingId));
var customers = new List<Customer>()
{
new Customer { CustomerId = "ALFKI", Name = "Alfred Kiss" },
new Customer { CustomerId = "ANATR", Name = "Ana Trorroja" }
};
Console.WriteLine("Q: There are duplicate customers?. A: {0} ", customers.HasDuplicates(x => x.CustomerId));
}
}
}

Linq To Entities Where Condition to Expressions comparison

I have 3 classes mapped with Entity Framework
public class A
{
public string Name { get; set; }
}
public class B
{
public string Name { get; set; }
public A A { get; set; }
}
public class C
{
public string Name { get; set; }
}
I have this Linq To Entities Where Condition
return queryableOfB.Where(b => b.A.Name = instanceOfC.Name);
Because this is a repetitive method in my logic, I want to create a method as:
protected void GetFilter<B, TBProperty, TCProperty>(
IQueryable<B> queryofB, C cModel,
Expression<Func<B, TBProperty>> bExpression,
Expression<Func<C, TCProperty>> cExpression)
{
var bExpValue = cExpression.Compile()(cModel);
queryofB.Where(b => b.Property.EndsWith(bExpValue)); // How can I compare two expressions? but adding "for example" an .EndsWith to expression 1?
}
It's important not to pass the .EndsWith in the expression because the decision of using EndsWith, StartsWith, Contains or exact comparison must be done in the method.
Thank you in advance Gurus.
actually where method expect function as predicate. you can try with below one.
its doing nothing just calling the where Extension method. its better to use there where method inline. But telling u the way how can u do it.
static IEnumerable<T1> M<T1>(IEnumerable<T1> objEnumerable, Func<T1, bool> wherePredicate)
{
return objEnumerable.Where(predicate);
}
// calling like
var listOfBObjects = GetBObjectIEnumerable();
C instanceOfC = GetCClassObject();
M<B>(listOfBObjects, b => b.A.Name = instanceOfC.Name);
update
you can use the
M<B>(listOfBObjects, b => b.A.Name.Equals(instanceOfC.Name));
M<B>(listOfBObjects, b => b.A.Name.StartsWith(instanceOfC.Name));
M<B>(listOfBObjects, b => b.A.Name.Contains(instanceOfC.Name));
to improve the performance and all. yes you can use the IQueryable rather than IEnumerable

LINQ Select statement with EF - object initializer reuse assignment

I have a case in my application where I create selects over an IQueryable in this manner:
myContext.Data
.Where(...)
.OrderBy(...)
.Select(p => new MyDataModel()
{
...
MyComplexProp = p.SomeProp.HasValue ? p.OtherProp.Name + " " + p.AnotherProp.Mark : p.EvenAnotherProp.Name,
...
});
Now, the assignment to MyComplexProp is used on multiple places and I'd like to extract it to a single place so I can reuse it. Does anyone have an idea on how to achieve this?
I cannot use a static method because the IQueryable must not be executed in this phase.
Add a new constructor to MyDataModel to take the entity as an argument and do the logic:
public class MyDataModel
{
public string MyComplexProp {get; set;}
//Include a default constructor
public MyDataModel()
{
}
//Include a default constructor
public MyDataModel(DataClass data)
{
MyComplexProp = data.SomeProp.HasValue ? data.OtherProp.Name + " " + data.AnotherProp.Mark : data.EvenAnotherProp.Name,
}
}
Then your linq would simplify to:
myContext.Data
.Where(...)
.OrderBy(...)
.AsEnumerable()
.Select(p => new MyDataModel(p));
Note the use of the AsEnumerable(). This will mean that the constructor can execute in memory, but you will still have deferred execution of the query.
To acheive full DB side execution you'll need the logic converted to an expression. You're probably into creating an expression tree.
I've already tested Extension Method for your question and It works.
Here is the sample code:
namespace MyExtensionMethods
{
//MyDataModel sample
public class MyDataModel
{
public int? SomeProp { get; set; }
public string OtherPropName { get; set; }
public string AnotherPropMark { get; set; }
public string EvenAnotherPropName { get; set; }
}
//The extension Method
public static class ExtensionMethod
{
public static string ToMyComplexProp(this MyDataModel p)
{
return p.SomeProp.HasValue ? p.OtherPropName + " " + p.AnotherPropMark : p.EvenAnotherPropName;
}
}
public class TestClass
{
MyDataModel myDataModel;
public TestClass()
{
myDataModel = new MyDataModel();
//This is the extension method and it's working
myDataModel.ToMyComplexProp();
}
}
}
If you tried extension methods and it didn't work for you, the you declared it incorrectly. The soul purpose of extension method is for situations like this (Like how Linq is using it).
I suggest you to check MSDN Extension Method example to use it properly.

How to write a generic test method to ensure that a class has a subset of properties of a separate class?

I am endeavoring to write a test method to determine if a class has a superset of properties of a different class. This is for purposes of mapping from domain objects to view model objects and as such there is no relationship between the two classes.
As an example if I had the domain class Foo and the view model class FooMap I would want to test that Foo had the properties that FooMap expected it to.
public class Foo
{
public string Bar { get;set; }
public string Baz { get;set; }
public string NoOneCaresProp { get; set; }
public string GetBarBaz() { return Bar + Baz; }
}
public class FooMap
{
public string Bar { get; set; }
public string GetBarBaz { get; set; }
public string NotAFooProp { get; set; }
}
Given the properties of FooMap for the purposes of this test I want to ensure that class Foo has the Bar property and the GetBarBaz method. Additional methods or properties for either class should be ignored. I've written the following static method to perform such a test but am not happy with my implementation:
public static void ExpectedPropertiesExist<TSource, TDestination, R>(params
Expression<Func<TDestination, R>>[] exclude)
{
var excludedProperties = exclude.Select(e => (e.Body as
MemberExpression).Member.Name);
var mappedProperties = typeof(TDestination).GetProperties()
.Select(p => p.Name)
.Except(excludedProperties);
var sourceType = typeof(TSource);
var baseTypeNames = sourceType.GetProperties().Select(b => b.Name).ToList();
baseTypeNames.AddRange(sourceType.GetMethods().Select(b => b.Name));
Assert.IsTrue(new HashSet<string>(baseTypeNames)
.IsSupersetOf(mappedProperties));
}
The code to call the above is not nearly as succinct as I would like it to be:
// what my call to the function looks like now
TestExtensionFun.ExpectedPropertiesExist<Foo, FooMap,
object>(fm => fm.NotAFooProp);
// I'd prefer it to look like this
TestExtensionFun.ExpectedPropertiesExist<Foo, FooMap>(fm => fm.NotAFooProp);
Nor am I sure that the method is as proficient as it could be. What is the best mechanism to write a generic test method to ensure that a class has a subset of properties of a separate class?
Since you don't really care what the expressions return (you are passing in object as the type for R), you could just remove the generic type parameter R from the ExpectedPropertiesExist method:
public static void ExpectedPropertiesExist<TSource, TDestination>(params
Expression<Func<TDestination, object>>[] exclude)
{
var excludedProperties = exclude.Select(e => (e.Body as
MemberExpression).Member.Name);
var mappedProperties = typeof(TDestination).GetProperties()
.Select(p => p.Name)
.Except(excludedProperties);
var sourceType = typeof(TSource);
var baseTypeNames = sourceType.GetProperties().Select(b => b.Name).ToList();
baseTypeNames.AddRange(sourceType.GetMethods().Select(b => b.Name));
Assert.IsTrue(new HashSet<string>(baseTypeNames)
.IsSupersetOf(mappedProperties));
}
This way, you can call the method with your desired syntax (only two generic type parameters).

Categories

Resources