LINQ query on object with unknown class - c#

I have an array of unknown (to the current method) class objects. I do know that each class has a property called "Number".
I am trying to write a LINQ query where I am looking for the object with the next Number in sequence. AKA, I'm at Number 8, use a LINQ query to find the object where Number=9.
Anyone got a suggestion?
Also, I use reflection often so don't worry about avoiding it.

You can create an interface - INumber with a property Number. Each of the objects that you are having in the array can implemen this interface.
That way, you will have an array of known type INumber. This way your query will be easy to debug and maintain.

If the objects all inherit from a known interface then you can cast them, e.g.
var next = items.Cast<IHasNumber>.FirstOrDefault(x => x.Number == index + 1);
If they don't, then you can use dynamic, e.g.
var next = items.Cast<dynamic>.FirstOrDefault(x => x.Number == index + 1);
If you have control of the types, then I would make them implement an interface so that you can use the first method, which should be significantly faster than the second. In that case, your collection will probably be IEnumerable<IHasNumber> to start with and you won't even have to cast.

If as you indicated elsewhere that you designed all the classes then you could put that number property in an in interface and have all the classes implement that interface. Then, in the linq query, use the interface.

If you truly do not have a common type that you can reduce to and for some reason cannot introduce such a type, then you may be able to use the dynamic keyword. I don't have access to a compiler at the moment, but can your method accept a collection of dynamic objects and query them?
For example:
IEnumerable<dynamic> collection = ...;
var numbers = from x in collection
select x.Number;

To avoid performance issues you can use the following method:
static void Main(string[] args)
{
object[] objs = GetInitialData();
var accessor = GetGetterHelper<int>(objs[0].GetType(), "Number");
var res = from a in objs where accessor(a) == 7 select a;
}
static Func<object, T> GetGetterHelper<T>(Type type, string methodName)
{
var methodInfo = type.GetProperty(methodName).GetGetMethod();
return x => (T)methodInfo.Invoke(x, new object[] {});
}

Related

How do I use the Type from my List<Type>?

I would like to make my code convention-based by using Types and keeping things simple, but generics has it's own complexity with it's own learning curve.
I have a bunch of POCOs (Plain Old CLR Objects) in a List that I'd like to iterate through later in the code.
var models = new List<Type>();
models.Add(typeof(Person));
models.Add(typeof(Company));
Would like to cycle through each list item:
models.ForEach(m =>
{
var label = m.FullName;
// var data = JsonConvert.DeserializeObject<List<typeof(m)>>(""); // doesn't work
var data = JsonConvert.DeserializeObject<List<m>>(""); // doesn't work either
...
}
The issue is that the "m" in the Deserialize line isn't working. What would be the best way to pass that through, i.e. making the 'List<m>' a 'List<T>' that we can use?
To use generics, you really need to know the Type (T) at compile time, you don't - you know it at run time. (Caveat: Its possible with reflection, but theres no need to use it when there's an overload as described below)
There is an overload of DeserializeObject which takes a Type rather than use generics. So your code would be
models.ForEach(m =>
{
var label = m.FullName;
var data = JsonConvert.DeserializeObject("",m);
...
}
However, as you've pointed out in comments you actually need a List<T> not a single T. You'll need a little bit of reflection, just to create the right type to pass to the above DeserializeObject call.
var tList = typeof(List<>); // Type of open List
models.ForEach(m =>
{
var label = m.FullName;
var tConvert = = tList.MakeGenericType(m);
var data = JsonConvert.DeserializeObject("",tConvert);
...
}
The answer to your question is above, but the more I look at it the harder it is to see what you can actually do with data. all you'll ever know about data is that it is an object. You cant cast it to anything - you wont know if its a list of Person or a list of Company.
Perhaps this was an overly contrived example you've used for a real-life problem. If not I forsee you're next problem is what to do with data!!
If you don't know the type at compile time you can do this with Reflection. Consider the following code:
models.ForEach(m =>
{
var mi = JsonConvert.GetType()
.GetMethod("DeserializeObject");
var m = mi.MakeGenericMethod(new[] { m });
// you pass [null] for the object because it's a [static] method
// and you don't have to declare [args] if you can express it simply
// but keep in mind that it's simply an object[]
m.Invoke(null, args);
}
Another solution is to call the generic method using reflection (if there isn't any overload that takes the type as parameter)
models.ForEach(m =>
{
MethodInfo method = typeof(JsonConvert).GetMethod("DeserializeObject");
MethodInfo generic = method.MakeGenericMethod(m);
generic.Invoke(null, "");
}

C#, instantiating a generic type - with variable type argument?

Code example:
void Foo(params object[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
var entry = new Entry<o.GetType()>(); // this doesn't work
entries.Add(entry);
}
...
}
Foo("hello", 5); // should fill entries with Entry<string> and Entry<int>
Why is that not possible? I guess I need to work with reflection instead? How to do that properly AND performant?
You just can't use C# generics the way you're trying to do in your snippet.
In order to use [C#] generics, the actual object type must be known at compile time.
You're trying to dynamically pass the object type as a type parameter. This is simply not possible.
Edit
Yes, it is possible to dynamically create generic objects using reflection. After all, generics is implemented both as a compile-time C# construct and as a .NET framework feature (as opposed to, say, Java, where it is only a compile-time feature based on Type Erasure). So, in .NET, through reflection, it is possible to implement the latter "bypassing" the former (which, again, would be impossible in Java).
But the OP clearly does not need that.
After all, entries is a List<IEntry>. IOW, the entries container does not "know" the concrete type of its elements (since it is bound to an interface). So, if each element to be add already implements IEntry, then this would be enough:
void Foo(params IEntry[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
OTOH, if those objects do not implement IEntry, then the OP just need a pure, ordinary, old-school list of untyped objects:
void Foo(params object[] objects)
{
var entries = new List<object>();
foreach(var o in objects)
{
entries.Add(o);
}
...
}
So using reflection in order to dynamically create a generic container, even if possible, seems to be overkill for this particular use case.
You can do it with reflection
var entryType = typeof(Entry<>);
Type[] typeArgs = { o.GetType() };
var genericType = entryType.MakeGenericType(typeArgs);
IEntry entry = (IEntry)Activator.CreateInstance(genericType);
You need a function of the form:
Func<Type, IEntry>
I would suggest adding a static function to the parent of Foo like this:
public static IEntry Make(Type type)
Inside that function, feel free to add whatever code makes sense to you:
if (type == typeof(string))
{
return new StringEntry(); //Obviously some special logic based on the type.
}
else
{
//Default logic
return (IEntry) Activator.CreateInstance(typeof(Entry<>).MakeGenericType(type));
}

What is the exact use of var keyword? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use of var keyword in C#
After discussion with colleagues regarding the use of the 'var' keyword in C# 3 I wondered what people's opinions were on the appropriate uses of type inference via var?
For example I rather lazily used var in questionable circumstances, e.g.:-
foreach(var item in someList) { // ... } // Type of 'item' not clear.
var something = someObject.SomeProperty; // Type of 'something' not clear.
var something = someMethod(); // Type of 'something' not clear.
More legitimate uses of var are as follows:-
var l = new List<string>(); // Obvious what l will be.
var s = new SomeClass(); // Obvious what s will be.
Interestingly LINQ seems to be a bit of a grey area, e.g.:-
var results = from r in dataContext.SomeTable
select r; // Not *entirely clear* what results will be here.
It's clear what results will be in that it will be a type which implements IEnumerable, however it isn't entirely obvious in the same way a var declaring a new object is.
It's even worse when it comes to LINQ to objects, e.g.:-
var results = from item in someList
where item != 3
select item;
This is no better than the equivilent foreach(var item in someList) { // ... } equivilent.
There is a real concern about type safety here - for example if we were to place the results of that query into an overloaded method that accepted IEnumerable<int> and IEnumerable<double> the caller might inadvertently pass in the wrong type.
Personally I find the circumstances you describe far from questionable, since there is no point in repeating yourself unless you specifically want the static type of a variable to be different than the static type of the expression used to initialize the variable. For example:
IEnumerable<int> foo = new List<int>(); // It's IEnumerable on purpose
Furthermore, there are absolutely no type safety concerns with var. The point is not that the variable can be of "any" type. It is of a very specific type, but you simply do not care to spell that type out.
I'm only using it as a place holder until I'm sure which datatypes I'm using.
Sure this is a short answer but I think it's pretty close that when you should use the var keyword.
the var keyword is used as shorthand in the language, but isn't a .NET type. The compiler must know the type of the variable to use the var keyword - so it is type-safe.
I personally only use it if the type name is also used in the assignment and the name is possible too long to duplicate in the code.
var dictionary = new Dictionary<string, string>();
It is also used for anonymous types (but still, the compiler must know the signature of the anonymous type).
var fred = new { Age = 23, Name = "Fred" };
This method is used commonly in the select clause of LINQ queries.
Just an "abstraction" or "syntax sugar" to be able to write a code without specifying first the type (this is no your first cases)
In second case: LINQ queries, instead, to rapresent some unknown, dynamic, not concrete, if you wish, type.
could be:
var results = from item in someList
where item != 3
select item; //item a class instance
could be
var results = from item in someList
where item != 3
select item.ItemName; //string property of that class
could be
var results = from item in someList
where item != 3
select new {item.ItemName, item.ID}; //unknown type dynamically generated, that conains the string and integer, like result
As far as I know var remains strong typed. The compiler calculated what the proper type should be. In fact it has no real meaning.
It is only a trick to reduce the number of manipulations. For instance when you change a type in one class, this can result in a cascade of modification. But its only a way to migrate work from the programmer to the compiler.
For instance your Linq query will result in a type IEnumerable<TA>. When you change some class so the result will be IEnumerable<TB> there is no need to change this part of the code.

Can this Linq query be typed as anything other than "var"?

When I do a query that returns an anonymous type
var assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new {p.Asset, p.Asset.PropertyTbl};
Can I type the return to anything other than var?
You cannot* return an anonymous type because the caller would not know what type it is and wouldn't be able to use it.
If you want to return the results, you can create objects of a non-anonymous type:
IEnumerable<Foo> assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new Foo { Bar = p.Asset, Baz = p.Asset.PropertyTbl};
You can also use the Tuple type in .NET 4 if you don't want to create a custom class for your values.
* This is not strictly true - it is possible but you should avoid doing it. Here is a link anyway if you really want to.
You can use object or dynamic (in .NET 4.0) instead of var but don't expect to find a name to an anonymous type. In your case using var is better as it will preserve the strong typing at least until you leave the scope of the current method.
You could define a new class:
public class AssetProp
{
public virtual string Asset {get;set;}
public virtual string PropertyTbl {get;set;}
}
And then you can return it as that class:
IEnumerable<AssetProp> assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new AssetProp {p.Asset, p.Asset.PropertyTbl};
Not really, since the new {p.Asset, p.Asset.PropertyTbl} code creates an anonymous type. Even using object doesn't really gain you much since you can't cast it to anything useful later on, so you would have to use reflection to access the properties.
Not really. If you cast to object you wont be able to access the properties of your anonymous class.
The var keyword was specifically introduced for dealing with anonymous classes - why would you want to avoid it? If you need to return the data you should name the class.
You can if you use lambda expressions, otherwise you can do a cast but do some good exception handling.
you can also do this (it does relate much to your problem though, because you just move "var" somewhere else, but it's interesting that it recognize those types as same)
var element = new { id = 7 };
List<object> collection = new List<object>();
element = collection.Select(item => new { id = 0 }).First();

C# - convert anonymous type to observablecollection

I have a LINQ statement that returns an anonymous type. I need to get this type to be an ObservableCollection in my Silverlight application. However, the closest I can get it to a
List myObjects;
Can someone tell me how to do this?
ObservableCollection<MyTasks> visibleTasks = e.Result;
var filteredResults = from visibleTask in visibleTasks
select visibleTask;
filteredResults = filteredResults.Where(p => p.DueDate == DateTime.Today);
visibleTasks = filteredResults.ToList(); // This throws a compile time error
How can I go from a anonymous type to an observable collection?
Thank you
As Ekin suggests, you can write a generic method that turns any IEnumerable<T> into an ObservableCollection<T>. This has one significant advantage over creating a new instance of ObservableCollection using constructor - the C# compiler is able to infer the generic type parameter automatically when calling a method, so you don't need to write the type of the elements. This allows you to create a collection of anonymous types, which wouldn't be otherwise possible (e.g. when using a constructor).
One improvement over Ekin's version is to write the method as an extension method. Following the usual naming pattern (such as ToList or ToArray), we can call it ToObservableCollection:
static ObservableCollection<T> ToObservableCollection<T>
(this IEnumerable<T> en) {
return new ObservableCollection<T>(en);
}
Now you can create an observable collection containing anonymous types returned from a LINQ query like this:
var oc =
(from t in visibleTasks
where t.IsSomething == true
select new { Name = t.TaskName, Whatever = t.Foo }
).ToObservableCollection();
Something like this would do the job using type inference features:
private static ObservableCollection<T> CreateObservable<T>(IEnumerable<T> enumerable)
{
return new ObservableCollection<T>(enumerable);
}
static void Main(string[] args)
{
var oc = CreateObservable(args.Where(s => s.Length == 5));
}
You should just be able to do this:
visibleTasks = new ObservableCollection<MyTasks>(filteredResults);
Are you sure that your object is an ObservableCollection indeed? If yes, you can just cast: visibleTasks = (ObservableCollection)filteredResults;
Try:
var filteredResults = from visibleTask in visibleTasks
where(p => p.DueDate == DateTime.Today)
select visibleTask).ToList();
(filteredResults will contain your desired list)

Categories

Resources