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.
Related
I have an "Test" class that has an IEnumerable of concrete objects
public class Test
{
public IEnumerable<MyObject> MyObjects { get; }
}
public class MyObject
{
public string Id { get; }
public MyObject(
string id,
{
this.Id = id;
}
}
When debugging my "Steps.cs" class used by my Specflow feature file, I noticed that the values for "Id" were changing.
They were as expected in the "Given" step and I added these to the ScenarioContext
[Given("I have use case (.*)")]
{
var _test = _retrieveTest.GetMyObjects(useCase);
ScenarioContext.Current.Add("test", _test);
}
They were changed when I read them out of the ScenarioContext in the "When" Step
[When("I do something")]
public void WhenIDoSomething()
{
var _test = (MyProject.Entity.Test)ScenarioContext.Current["test"];
}
The solution to stop the values changing was to use the LINQ "ToList()" call when retrieving the object as shown below:
private IEnumerable<MyObject> GetMyObjects(
string usecase,
MyProject.Entity.Test test)
{
...
return testData.Objects
.Select(Object => {
var _id = var _id = Guid.NewGuid();
return new MyProject.Entity.MyObject(
_id);
}).ToList();
}
Can anyone explain why it is necessary to call ".ToList()" here and without it why the value of "Id" changes in the "ScenarioContext " between the "Given" and "When" steps
Without the .ToList() you have return an Enumerator that is executed everytime you iterate over it.
With the .ToList() you materialize the enumerator and have a concrete list.
See IEnumerable vs List - What to Use? How do they work? for a more detailed answer.
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
}
}
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));
}
}
}
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
I have the following business objects:
public abstract class Product
{
public int Id { get; set; }
public bool OnStock { get; set; }
}
public class ProductForImport : Product
{
public int ImportId { get; set; }
}
public class ProductForExport : Product
{
public int ExportId { get; set; }
public bool IsExportable { get; set; }
public bool IsUsable { get; set; }
public string OtherParam {get; set;}
public static implicit operator ProductForExport(ProductForImport pfi)
{
ProductForExport p = new ProductForExport();
p.Id = pfi.Id;
p.IsExportable = true;
p.ExportId = 0;
return p;
}
}
so I can convert between the two types:
static void Main(string[] args)
{
ProductForExport pfe = new ProductForExport();
pfe.Id = 1;
pfe.OnStock = true;
ProductForImport pfi = new ProductForImport();
pfi.ImportId = 200;
ProductForExport pfe2 = (ProductForExport)pfi;
}
this works OK.
I have 100.000 ProductsForImport items.
If I understand correctly, if I convert them to ProductsForExport items, I'll have 100.000 +100.000 items in memory - that's reasonable.
My problem is: I have to send these "ProductForExport" objects through JSON services, each service just need some subset of the properties of each type:
servicecall1 should return ProductForExport1{ExportId,IsExportable}
servicecall2 should return ProductForExport2{ExportId,IsUsable}
Question: should I write an implicit conversion similar to the above example for these new types - ProductForExport1 and ProductForExport2 (so basically create 100.000+100.000 new objects)
or
somehow can I just "hide" the unwanted properties with some magic from the original type without the need to create new instances?
thanks,
b.
If you ned such kind of decoupling and separation of entities - you can create DTO object along with each business object and use DTO to communicate with Service.
But if you have a lot of business entities consider an other approach to avoid maintenance hell.
public sealed class ExportProductDto
{
public(ProductForExport exportProduct)
{
// initialize fields
this.ExportId = exportProduct.ExportId;
}
public int ExportId { get; private set; }
}
BTW,
An overkill solution with operator overload, use Adapter pattern to convert between product types
To decouple adapting from entities itself implement following interface your self:
public interface IProductAdapter<TImport, TExport>
{
TImport ToImportProduct(TExport exportProduct);
TExport ToExportProduct(TImport importProduct);
}
Or an other adapter approach:
// Implement this interface for ProductForImport class
// public class ProductForImport : IExportProductAdapter, Product
public interface IExportProductAdapter
{
ProductForExport ToExportProduct();
}
// Implement this interface for ProductForExport class
// public class ProductForExport : IImportProductAdapter, Product
public interface IImportProductAdapter
{
ProductForImport ToImportProduct();
}
EDIT: Answer to comments
// An example of IExportProductAdapter adapter implementation
public sealed class ProductForImport : Product, IExportProductAdapter
{
public int ImportId { get; set; }
public ProductForExport ToExportProduct()
{
ProductForExport p = new ProductForExport();
p.Id = this.Id;
p.IsExportable = true;
p.ExportId = 0;
return p;
}
}
And then instead of:
ProductForExport pfe2 = (ProductForExport)pfi;
You can do:
ProductForExport pfe2 = pfi.ToExportProduct();
I would create light objects specifically for returning through the service with only the required fields. Then use Automapper or something like that to map them.
I don't recommend using operator overloading if you can avoid it. I have seen many issues where a developer didn't realize when the operator overload was being called and something unexpected happened.
If you are using WCF, you can apply the IgnoreDataMemberAttribute to properties you wish not to serialize.
Have a look at the ScriptIgnoreAttribute to exclude properties from json serialization.
It took me a few reads but I don't think your problem is about implicit conversion as much as how to send data via json right?
If you have your object collections of Import or Export object you can use the JavaScriptSerilizer and some anonymous types to slice and dice what data you send.
You can use Linq to select specific properties of your object in a collection, and define an anonymous type "on-the-fly" to serialize out as a json string like this:
List<ProductForExport> exportList; //the list to export
JavaScriptSerializer jss = new JavaScriptSerializer();
string output = string.Empty;
output = jss.Serialize(new
{
isExportable = True, //static named properties
iTotalProducts = exportList.Count, //dynamic values
productDataArray = exportList //all data in an array object
});
//Or build the result using just a few properties of the collection:
foreach (ExportProduct exProd in exportList)
{
output += jss.Serialize(new
{
exProd.IsExportable,
exProd.ExportID
});
}