.Where with LINQ on custom collection? - c#

I'm trying to return a collection of items, from an existing ConcurrentHashSet but only selecting the ones by a certain ID, I've coded the LINQ for it, the only thing I'm struggling with is it returns a IEnumerable and I have a custom ConcurrentHashSet class and I'm unsure how to convert it?
I've tried casting it using (ConcurrentHashSet) but it hasn't worked, my ConcurrentHashSet does implement IEnumerable so I'm guessing it is possible..
public ConcurrentHashSet<Item> GetItemsById(int id)
{
return Items.Where(x => x.HasLoaded && x.Id == id);
}

.Where returns an IEnumerable<T> and you cannot change that. Explicit casting as you tried does not work because through every ConcurrentHashSet is an IEnumerable (inherits), an IEnumerable is not necessarily a ConcurrentHashSet. The compiler can't say.
Either instantiate a new ConcurrentHashSet (assuming it has a
constructor receiving an IEnumerable, which it should have):
return new ConcurrentHashSet<Item>(Items.Where(x => x.HasLoaded && x.Id == id));
Or change your method to return IEnumerable<Item>

Code below returns a collection since it is enumerable in a foreach :
public class Test
{
ConcurrentHashSet hashSet = new ConcurrentHashSet();
public Test()
{
foreach (ConcurrentHashSet set in hashSet.GetItemsById(123))
{
}
}
}
public class ConcurrentHashSet : HashSet<ConcurrentHashSet>
{
public Boolean HasLoaded { get; set; }
public int Id { get; set; }
public List<ConcurrentHashSet> GetItemsById(int id)
{
return this.Where(x => x.HasLoaded && x.Id == id).ToList();
}
}

Related

Identifying TypeOf value of Property Attributes as existing Class name

I am trying to iterate through Classes who have properties not linked to other Classes (i.e.
public SomeOtherClass code { get; set; }
In my attempt and thanks to other people's advice, I came up with the following, which iterates through the classes of a specific namespace (i.e. Library = "ConsoleApp1.Library" etc) as:
var classes = AppDomain.CurrentDomain.GetAssemblies ()
.SelectMany (t => t.GetTypes ())
.Where (t =>
t.IsClass &&
t.Namespace == Library &&
!t.IsNested)
.ToList ();
and getting properties as
var properties = classes.SelectMany (x => x.GetProperties (BindingFlags.Public | BindingFlags.Instance)
.Select (y => y.PropertyType));
while I get what I need from a foreach loop:
foreach ( var method in classes.Where
(x => !properties.Contains(x) && !properties.Contains (x))
.Select (x => x.Name) )
{
// some work here
}
However, some cases slipped through my selection; cases where the class has the below Properties as Array, ICollection, List and Dictionary:
public class TopObject
{
[JsonProperty("ex")]
public OtherResults ex { get; set; }
[JsonProperty ("Results")]
public OtherResults Results { get; set; }
private readonly OtherResults[,] Codes1 = new OtherResults[9, 9];
public ICollection<OtherResults> Codes2 { get; set; }
public List<OtherResults> Codes3 { get; set; }
public Dictionary<int, OtherResults> Map { get { return _map; } }
public TopObject()
{ Results = new OtherResults (); }
}
public class OtherResults
{
[JsonProperty ("Jcodes")]
public string Jcodes { get; set; }
public OtherResults()
{ }
}
I need help in editing the var method, to include (additionally) the cases where a property has Dictionary Value type any of the classes, or is Array of type of any of the classes, or is ICollection or List who accept any knows classes.
Kindly someone can help me with this thing? Thank you very much
So I finally had time to play around with this a bit. If I understand correctly you would like something like this:
First we create a helper function that extracts all referenced types:
public static IEnumerable<Type> GetReferencedTypes(Type type)
{
if (type.IsArray)
return new List<Type> { type, type.GetElementType() };
if (type.IsGenericType)
return type.GetGenericArguments().SelectMany(GetReferencedTypes)
.Union(new List<Type>{type});
return new List<Type>{ type };
}
I can't guarantee that this covers everything but atleast it seems to get all the references from your examples. Array is special here, it's not a generic but we have to extract it's underlying type. All generic types we extract recursively. and if it's not any of those we just return the type that was given.
So with this helper function we can now do something like this:
var currentAssembly = typeof(Program).Assembly;
var currentAssemblyName = typeof(Program).Assembly.GetName().Name;
var types = currentAssembly.GetTypes();
var classes = types.Where(type => type.IsClass && !type.IsNested).ToList();
var referencedTypes = classes.SelectMany(c => c.GetProperties().SelectMany(p => GetReferencedTypes(p.PropertyType))).Where(type => type.Assembly.GetName().Name == currentAssemblyName).Select(type => type.Name)
.Distinct().ToList();
We get the current assembly. Get all types, then put all properties of those types through our helper function, select their name, remove duplicates and create a list. Which results in:
["Method100Response201_01", "Method600Response100", "Method700Response100", "Method100Response404_01"]
Keep in mind that in your fiddle change the public Method500Response100[,] Codes1 = new Method500Response100[9, 9]; is not returned by the GetProperties() call (it has no { get; set; }).
Hope this helps

How to use LINQ to query a [key] property using generic types?

Let's say I have a class:
public class Customer
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
And now I want to create a generic Get() method that might query Customer or any one of several other classes that also have a [key] field defined.
public T Get<T>(int id)
{
string json = DoSomething(); // <-- making it easy for this post
List<T> items = JsonConvert.DeserializeObject<List<T>>(json);
return items.FirstOrDefault(i => i. ????? = id);
}
I'm not sure how to use Linq to generically specify the [key] field.
Thanks!
Hope this helps:
public interface IBase
{
int Id { get; }
}
public class Customer : IBase
{
public string Name { get; set; }
public int Id { get ; set ; }
}
public T Get<T>(int id) where T : IBase
{
string json = DoSomething(); // <-- making it easy for this post
List<T> items = JsonConvert.DeserializeObject<List<T>>(json);
return items.FirstOrDefault(i => i.Id == id);
}
Just implement the interface IBase in all other classes.
For what is worth I think using contracts is a better way to solve this. But in case you or someone else actually need to check for the attribute here's the answer:
public static T Get<T>(int id)
{
string json = DoSomething(); // <-- making it easy for this post
List<T> items = JsonConvert.DeserializeObject<List<T>>(json);
return items.FirstOrDefault(
item => (int)item.GetType()
.GetProperties()
.FirstOrDefault(
p => Attribute.IsDefined(p, typeof(KeyAttribute))
).GetValue(item) == id
);
}
As far a this part of your question:
I'm not sure how to use Linq to generically specify the [key] field.
The attribute is KeyAttribute you can know that by navigating to the definition (pressing F12 if you're using VS or checking the docs in case your editor doesn't support this feature.
Things to consider:
this is using Reflection reasonably heavily, so it will never have the best performance. That being said you can cache the result from GetProperties() somewhere for faster lookups.
It's hardcoding the cast to int but it appears that's what you're after.
If the collection is null it'll throw an exception.

HashSet initialized using IEnumerable contains duplicate elements

I want to be able to use HashSet constructed from IEnumerable collection of custom objects without duplicates. My custom object contains id and some other properties which aren't important for this question. I make a query to a database which returns an IEnumerable that I later use to construct a HashSet with the following code:
HashSet<Question> results = new HashSet<Question>(new QuestionComparer());
var result = await query.ExecuteNextAsync<Question>();
results.UnionWith(result);
The problem is there are duplicate records inside the result collection which I do not want.
The QuestionComparer class looks like this:
public class QuestionComparer : IEqualityComparer<Question>
{
public bool Equals(Question x, Question y)
{
return x != null && y != null && x.Id == y.Id;
}
public int GetHashCode(Question obj)
{
return obj.Id.GetHashCode();
}
}
I also tried overriding both Equals and GetHashCode methods inside the Question class but no success. I considered looping through the collection and removing the duplicates, but it seems like it may become a performance problem...
EDIT: Azure DocumentDB that I am using apparently does not currently support a "distinct" type of query.
Instead of writing a public class QuestionComparer you should override the methods of the existing Question class
public class Question
{
public string ID { get; set; }
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(System.Object obj)
{
return (obj != null && obj is Question) ? (this.ID == ((Question)(obj)).ID) : false;
}
}
So duplicates are not possible. Sample:
HashSet<Question> qh = new HashSet<Question>();
qh.Add(new Question() { ID = "1" });
qh.Add(new Question() { ID = "1" }); //will not be added
qh.Add(new Question() { ID = "2" });
https://dotnetfiddle.net/wrFTaA

Using LINQ with wrapped arrays

I'm new to LINQ and I'm doing a simple project to learn the features of the technology.
Currently I've got a static class that wraps an array of object (a kind of simple factory). Let's say it looks like the following:
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
// ...
}
Now I can add some functions to my Factory that allow me to query the inner array, e.g.
public static Item GetByID(ItemID id)
{
var query =
from item in items
where item.ID == id
select item;
return query.First();
}
However, this requires me to modify the internals of the Factory class. Is there a way to write such queries from the 'outer world' instead ?
public class OtherClass
{
var result = from it in Factory select ...
}
?
Yes, you can. Just use linq on the Factory from the 'outer world':
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Items.SingleOrDefault(i => i.ID == id);
}
}
Of course, to do this, you'd need to change the access modifier of the items array to be public.
There are so many options.
The easiest thing to do is just to expose a public property that allows just what you want to have allowed:
public static class Factory
{
private static Item[] items = new Item[]
{
// items are created here
};
public static IEnumerable<IReadableItem> Items{ get { return items; } }
// ...
}
The above code assumes that the Item class implements an IReadableItem interface that only has the methods and properties on it that you want to allow people to access. You could also clone the items list before returning it each time, if you're worried someone might re-cast the Items or try to modify it using reflection. Because the standard LINQ methods all work off of IEnumerable<>s, this would allow someone to effectively produce a LINQ query on your items, without exposing overmuch data.
List<string> bestItemNames = Factory.Items.Where(i => i.IsBest)
.Select(i => i.Name)
.ToList();
If you wanted to get really fancy, you could even implement your own LINQ provider. From a language perspective, LINQ expression syntax just maps to specific method names, so if you had a class that implemented a .Where() and a .Select() method, then you could implement that pretty much however you wanted, and people wouldn't know any different until they tried doing something that your methods didn't support.
One possibility is to implement IQueryable<T> for a non-static class:
public class Factory<T> : IQueryable<T>
{
protected T[] _items = new T[]{};
public Type ElementType
{
// or typeof(T)
get { return _items.AsQueryable().ElementType; }
}
public System.Linq.Expressions.Expression Expression
{
get { return _items.AsQueryable().Expression; }
}
public IQueryProvider Provider
{
get { return _items.AsQueryable().Provider; }
}
public IEnumerator<T> GetEnumerator()
{
return ( IEnumerator<T> )_items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _items.GetEnumerator();
}
}
Derive non-generic class to populate array (if desired)
public class ItemFactory : Factory<Item>
{
public ItemFactory()
{
// items are created here
}
}
Create static instance
public static class Factories
{
private static ItemFactory _itemFactory = new ItemFactory();
public static ItemFactory ItemFactory { get { return _itemFactory; } }
}
Usage:
var specificItem = Factories.ItemFactory
.Where( item => item.ID == id )
.SingleOrDefault();
use an expression tree
public class OtherClass
{
public Item Get(ItemId id)
{
return Factory.Get(i => i.id == id);
}
}
and change the get method to
public Item Get(Expression<Func<Item,bool>> filter)
{
return items.SingleOrDefault(filter);
}
however, this approach makes little sense unless you are encapsulating some other logic in your factory class i.e. select only rows that are not soft deleted.

C# Linq where clause according to property name

Let's say I have the following class :
public class Person {
public string FirstName { get; set; }
public string SurName { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
Also, I have the following method and I am reaching out to person data via a repository.
public IEnumerable<Person> getPeople(string searchField, string searchTerm) {
//_repo.GetAll() returns IEnumerable<Person>
var model = _repo.GetAll();
//Need the logic here for filtering
return model;
}
As you can see I am getting two parameter for the method : searchField and searchTerm.
searchField is for the field name whose value will be used for filtering. searchTerm is the value which will be used to compare with retrived value (sorry if I am not clear here but this is the most I can come up with)
What I would normally do is as follows :
public IEnumerable<Person> getPeople(string searchField, string searchTerm) {
//_repo.GetAll() returns IEnumerable<Person>
var model = _repo.GetAll();
switch(searchField) {
case "FirstName":
model = model.Where(x => x.FirstName == searchTerm);
break;
case "SurName":
model = model.Where(x => x.SurName == searchTerm);
break;
//Keeps going
}
return model;
}
Which will work just fine. But if I make a change on my class, this code will have a change to break or be in lack of some functions if I add new properties this class.
What I am looking for is something like below :
NOTE :
This below code completely belongs to my imagination and there is no such a
thing exists.
model = model.Where(x => x.GetPropertyByName(searchField) == searchTerm);
Am I flying too high here if it is impossible or being complete idiot if there is already a built in way for this?
Looks like you need Dynamic Linq queries:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
I use this extension method to achieve what you want.
public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> source, string propertyName, string value)
{
Expression<Func<TEntity, bool>> whereExpression = x => x.GetType().InvokeMember(propertyName, BindingFlags.GetProperty, null, x, null).ObjectToString().IndexOf(value, StringComparison.InvariantCultureIgnoreCase) >= 0;
return source.Where(whereExpression);
}
Note: ObjectToString is just another extension method that returns string.Empty if the Object passed in is NULL
For linq2Object You can use reflection as bellow(it's not very fast):
model.Where(x => x.GetType().GetProperty(propName).GetValue(x, null) == propVal);
but for linq2Entity I think this doesn't work, it works for linq2objects.
I think the following implementation looks an awful lot like what you originally intended, although changing this to a generic method likely makes more sense.
public IEnumerable<Person> getPeople(string searchField, string searchTerm) {
PropertyInfo getter=typeof(Person).GetProperty(searchField);
if(getter==null) {
throw new ArgumentOutOfRangeException("searchField");
}
return _repo.GetAll().Where(x => getter.GetValue(x, null).ToString()==searchTerm);
}
This should be type-safe:
public IEnumerable<T> Where<T,U>(Func<T,U> propertySelector, U value)
{
return model.Where(x => propertySelector(x) == value);
}
usage:
Where((MyClass x) => x.PropertyName, propertyValue);
Or:
public IEnumerable<T> Where<T>(Func<T,bool> entitySelector)
{
return model.Where(entitySelector);
}
usage:
Where<MyClass>(x => x.PropertyName == propertyValue && x.OtherProperty == otherValue);
Use Reflection
model = model.Where(x =>
((string)x.GetType().GetProperty("searchField").GetValue(0, null)) == searchTerm);
Rather than messing with reflection, custom expression trees, etc., when using Entity Framework, consider using the Builder Method extensions to the standard LINQ operators which take strings rather than lambdas. These are much easier to build for dynamic query requirements:
string filter = String.Format("it.{0} = #value", fieldName);
var model = context.People.Where(filter, new ObjectParameter("value", searchValue));
Of course, this would mean that you yould need to modify your repository to return IObjectSet rather than IEnumerable. It would perform better as well. By returning IEnumerable, you are hydrating every row in your database to your repository and then filtering via LINQ to Objects rather than applying the filter back in your database.
For more information about the Builder Methods in EF, see the BuilderMethodSamples.cs in http://archive.msdn.microsoft.com/EFQuerySamples/Release/ProjectReleases.aspx?ReleaseId=4422.

Categories