I have an ICollection with objects:
private ObservableCollection<ViewItem> items;
The viewItems have no properties. The data will be accessed via an index with
public object this[int index] {
get{ .... }
set {....}
}
I have a geneal class for filtering. The linq with properies will work fine. I use (the important code only):
Queryable = CreateQueryable((IEnumerable<object>)mItemsSource.SourceCollection, ItemType);
mQuery = Queryable.Where(filterString).Cast<object>();
ilteredCollection = mQuery.ToList();
with:
private static IQueryable CreateQueryable(IEnumerable<object> collection, Type itemType)
{
if (itemType == null) return null;
var queryableList = collection.AsQueryable();
return queryableList.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Cast",
new Type[] { itemType },
queryableList.Expression));
}
So I can use a filter string like: Id>10 or Name="abc"
where Id and Name are property names.
But I have also Object in another collection which only have access via index. so I have an where string like:
[0]>10 or [1]="abc"
I didn't find any solution. The only hint I could find is to use:
new(it([idx] as Type)
where idx is element index and Type is a type of this element
e.g.
[0]>10 --> new(it[0] as object)>10
But than I get the error:
{"Operator '=' incompatible with operand types 'DynamicClass1' and 'Int32'"}
Useing a string in my filter like:
new(it[0] as object)>"10"
than the error is:
{"Operator '=' incompatible with operand types 'DynamicClass1' and 'string'"}
So - how can I solve this problem. Because this is a general Filterclass I also don't know the type. So in the as statement I can only use object or something like this.
I hope anyone can help me. Perhaps the dynamic keyword of C# 4.0 will help??
BTW a workaround will be to impement a wrapper in each class with indexer, but this will be a lot of stupid work. And that is something a real programmer don't like ;). I am sure there is a solution!
Cheer up !!
First of all -- How to access Current Instance ?
When parsing a lambda expression with a single unnamed parameter, the members of the unnamed parameter are automatically in scope in the expression string, and the current instance given by the unnamed parameter can be referenced in whole using the keyword it. For example,
customers.Where("Country = #0", country);
is equivalent to
customers.Where("it.Country = #0", country);
Above concept has been explained here.
From above explanation, we can now access the indexer property as it[#0] where #0 is value of index to be passed, as explained below.
//Consider below class
public class Product
{
private NameValueCollection collection = new NameValueCollection();
public string Company { get; set; }
public string Distributor { get; set; }
public int ID { get; set; }
...
public string this[string index]
{
get { return collection[index]; }
set { if(!string.IsNullOrEmpty(value)) collection[index]=value; }
}
}
//Main Code
List<Product> list = new List<Product>();
Product product = new Product() { Company = "Nestle", Distributor = "xyz", ID = 1 };
product["Name"] = "Maggi";
list.Add(product);
var filteredList = list.AsQueryable().Where("it[#0]=#1", "Name", "Maggi"); //Accessing the current item by indexer property
foreach (Product productItem in filteredList)
{
Console.WriteLine(productItem.Company);
}
Hope this helps you !! :)
Your usage of new keyword is wrong.
It does not cast object (nor does as).
Keyword new is used to create new object of anonymous class with the specified properties.
Thus new(it[idx] as Type) will create new object with property Type having the value it[idx]. It is equivalent to C#'s: new { Type = this[idx] }.
As I have already pointed out in Dynamic linq: Is there a way to access object data by index?, you need to cast it in the following manner: Int32(it[0]) > 10 for your pseudo-query [0] > 10.
Related
I'm trying to do a dynamic query to one of myTables
For that I'm usin the following function:
public async Task<bool> search(DBContext db, M model, string uniqueNonIDField)
{
Type modelType = model.GetType();//get model of generic
object modelInstance = Activator.CreateInstance(modelType);
PropertyInfo field = modelType.GetProperty(uniqueNonIDField); //get property to get existing value
if (field == null)
throw new Exception(string.Format("Campo {0} Não encontrado", uniqueNonIDField));
string value = (string)field.GetValue(model, null); //get value to search in myTable
field.SetValue(model, Regex.Replace(value, #"[\u002D\u2010\u2012\u2013\u2014]", "-"), null); //do some clean up
value = (string)field.GetValue(model, null); //get new value after being cleaned
if (db.Set(modelType).Where(String.Format("#0=#1", uniqueNonIDField, value)).Count() == 0) //Test if there is already any object in myTable with that value.
{...do stuff}
...
}
But there is an error:
System.Linq.Dynamic.ParseException: No property or field '0' exists in type 'myTable'
If I hardcode all expression like:
if (db.myTable.Where("existingField=123").Count() == 0){...}
the error persist with:
System.Linq.Dynamic.ParseException: No property or field '123' exists in type 'myTable'
I'm trying to do as exemplified in many examples and saw many other stackoverflow similar answers, but can't find the reason for the error. Rookie mistake probably.
Can you please help me finding it?
You can pass a string to the where statement. System.Linq.Dynamic allows you to filter by string.
Everything seems to be okay in your code and maybe your issue is related to this one:
https://github.com/zzzprojects/System.Linq.Dynamic/issues/101
Are you using this code under dotnetcore? If yes then please install the related NuGet package and change the using to System.Linq.Dynamic.Core
You cannot pass your where statement as a string like this: Where("existingField=123"), you do it as an expression Expression<Func<TSource,bool>> predicate. In order to pass that expression you will have to know the type for which you want to filter
EDIT: Sample Where
Lets say you have MyClass in your DbContext like this:
public class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MyContext : DbContext
{
public DbSet<MyClass> MyClass { get; set; }
}
Then to filter on the Name or Id property of MyClass, all you do is:
var filteredEntities = dbContext.MyClass.Where(x => x.Name == "test").ToList();
I have a class that used to have a string return type. Now I find I need to return more than a string. I was thinking to return something like below:
public string Test()
{
return ( new { ID = 5, Name= "Dave" } );
}
Is this even possible and if so then what would be the return type? I know it's not string ..
As others have said, the best thing to do here is to make a nominal type. I would suggest that the nominal type have the same characteristics as an anonymous type; that is, you should consider making the type immutable and consider making it exhibit value equality.
It is possible to return an anonymous type as object and then use the instance returned elsewhere using a variety of sneaky techniques. You can cast the object to "dynamic" (in C# 4) and then use the properties of the anonymous type, but this is slow and lacks compile-time type checking.
You can also use the "cast by example" trick, which does get you compile-time type checking. However, that trick only works when the anonymous source object and the anonymous example object come from the same assembly.
static T CastByExample<T>(object source, T example) where T : class
{
return source as T;
}
static object ReturnsAnonymous() { return new { X = 123 }; }
static void DoIt()
{
object obj = ReturnsAnonymous();
var example = new { X = 0 };
var anon = CastByExample(obj, example);
Console.WriteLine(anon.X); // 123
}
See how sneaky that is? We use method type inference and local variable type inference to tell the compiler "these two things are the same type". This lets you export an anonymous type as object and cast it back to anonymous type.
But you probably should not do this; if you're resorting to such sneaky tricks then you should simply be defining a nominal type in the first place. Also, like I said, the trick only works if the example and the source objects were created in code in the same assembly; two "identical" anonymous types in two different assemblies do not unify to be the same type.
The object that you return does have a class, but it's anonymous so you can't specify it in the code. You just have to return it as an object reference:
public object Test() {
return new { ID = 5, Name= "Dave" };
}
Note that the anonymous type is unknown outside the scope of the method, so reflection is the only way to access its properties.
If you want to be able to use the returned object conveniently, you should declare a class:
public class TestResult
{
public int ID { get; set; }
public string Name { get; set; }
}
public TestResult Test() {
return new TestResult() { ID = 5, Name= "Dave" };
}
Another alternative is to use an existing class, if it fits your purpose. A KeyValuePair is close to what you use, but then the properties will of course be named Key and Value instead of ID and Name:
public KeyValuePair<int, string> Test() {
return new KeyValuePair<int, string>(5, "Dave");
}
This isn't possible as the anonymous class is only valid within the current context. If you need to return an object then you'll need to create a real class.
I'm assuming you left string as the return type by accident.
Anonymous type are class type that are derived directly from object.
You can return it from method as object as return type.
Have a look at this.
No, it's not possible. Your options are:
Define a real class for the return value,
Use System.Tuple, or
Use out parameters (probably the least good option).
You can make a struct (or class) for this.
public struct IdAndName
{
public int Id;
public string Name;
public IdAndName(int id, string name)
{
ID = id;
Name = name;
}
}
You could also use a Tuple<T1, T2>, (but that's not recommended as the properties aren't named.
class NewString
{
public int ID { get; set; }
public string Name { get; set; }
}
public NewString Test()
{
return ( new NewString() { ID = 5, Name = "Dave" } );
}
:)
So I have this LINQ query that ends in a custom select kinda like this:
select new { this1 = table.this1, this2 = othertable.this2 }
The call to that query from the Controller looks something like this:
ViewData["these"] = theRepo.GetAllThese(someVar, anotherVar);
Now when I pass this on to my view since it is not strongly typed how can I iterate through it with a foreach, how can I cast it as an IQueryable or a List if I don't know what's in it?
...is it something like this?
IQueryable<???> these = ViewData["These"];
foreach (var this in these) {...
Just need to know what to put for '???' I think.
You cannot use an anonymous type (select new { Property = value }) outside the scope in which it is defined. So you should use foreach(var x in {yourQueryHere}) from within the method you defined the query in.
Example:
This is possible:
public void myMethod() {
var x = from c in IEnumerable select new { Prop = value };
foreach (var y in x) {
}
}
This is impossible:
public void myMethod() {
foreach (var y in myMethod2()) {
}
}
public IQueryable<???> myMethod2() {
return from c in IEnumerable select new { Prop = value };
}
Your linq query returns a collection of anonymously typed objects. Being anonymous, there is no way to "call their name" when declaring an explicitly typed variable. Thus, the true type/shape of the objects is only known within the action method where the objects are defined.
The indexed getter of the ViewData object has a return type of object, and without knowing the type name, you want be able to cast the return value of ViewData["these"] to anything useful.
What you might want to do instead, is to create a model - more specifically a "view model" - which defines the structure of the objects you are selecting using LINQ:
public class FoobarViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
and redefine your query to do a select like this:
select new FoobarViewModel { foo = table.this1, bar = othertable.this2 }
Your objects now share a common named class, and your collection can be easily casted to the proper type in the view.
I am attempting to use Linq to project each row from a DB query into a dictionary that has a custom type as its value. I am unsure of the LINQ syntax to do this?
This is my current attempt (which doesn't compile, but should demonstrate what I am trying to do). I am having trouble with the 'select new...' part.
public class MyClass
{
public Dictionary<int, CustomType> dict;
}
public class MyType{
string Name;
decimal Value;
}
var result = (from t in table
select new {
t.Id,
new MyType(t.Name,t.Value)
}).AsEnumerable().ToDictionary();
ANSWER:
Thanks Jason. I just used properties and automatic initialisers rather than a constructor. The working code resembles this (any improvements to this are welcome):
public class MyType {
public string Name {get;set;}
public decimal Value { get; set;}
}
Dictionary<int, CustomType> dict;
dict = (from t in table
select new {
id = av.Account.Id,
mt = new MyType { Name = t.Name, Value = t.Value }
}).ToDictionary(item => item.id, item => item.mt);
MyType doesn't have a constructor that takes two arguments.
Add the following to the definition of MyType:
public MyType(string name, decimal value) {
Name = name;
Value = value;
}
Further, you did not give the anonymous type member defined by
new MyType(t.Name, t.Value)
a name; try changing that line to:
MyType = new MyType(t.Name, t.Value)
The compiler will yell at you that it can not discern a name for this anonymous member.
Finally, there isn't an overload of ToDictionary that has no arguments. Assuming you named the above anonymous member to be MyType, change the call to ToDictionary to be
....ToDictionary(item => item.Id, item => item.MyType);
Consider this:
var me = new { FirstName = "John", LastName = "Smith" };
This is fine as we can then do this:
Console.WriteLine("{0} {1}", me.FirstName, me.LastName);
However we can't do this:
public T GetMe()
{
return new { FirstName = "John", LastName = "Smith" };
}
because we don't know the type of T.
We could do this:
public object GetMe()
{
return new { FirstName = "John", LastName = "Smith" };
}
but then we'd have to inspect the properties of the object using reflection in order to access them:
var p = new Prog();
object o = p.GetMe();
Type t = o.GetType();
foreach (var prop in t.GetProperties())
{
Console.WriteLine(prop.Name + ": " + prop.GetValue(o, null));
}
However what about if we could name an anonymous type as we define it? Of course it would no longer be anonymous, however it would be more succinct and maintainable than a normal class definition.
Consider this:
public Person GetMe()
{
return new public class Person { FirstName = "John", LastName = "Smith" };
}
The benefit being it would then be possible to return the result of a complicated Linq query from a method without having to define the class explicitly.
Consider this relatively complex Linq query:
List<int> list = new List<int>();
var query = from number in list
select
new
{
Number = number,
Square = number*number,
Absolute = Math.Abs(number),
Range = Enumerable.Range(0, number)
};
Instead of defining a class like so:
public class MyNumbers
{
public int Number { get; set; }
public int Square { get; set; }
public int Absolute { get; set; }
public IEnumerable<int> Range { get; set; }
}
in order to return the query variable from a method we could instead just do this:
List<int> list = new List<int>();
return from number in list
select new public class MyNumbers
{
Number = number,
Square = number*number,
Absolute = Math.Abs(number),
Range = Enumerable.Range(0, number)
};
Actually, there's a "hack" that you can do to get an anonymous type back from a method. Consider this:
public object MyMethod()
{
var myNewObject = new
{
stringProperty = "Hello, World!",
intProperty = 1337,
boolProperty = false
};
return myNewObject;
}
public T Cast<T>(object obj, T type)
{
return (T)obj;
}
You can now do this:
var obj = MyMethod();
var myNewObj = Cast(obj, new { stringProperty = "", intProperty = 0, boolProperty = false });
The myNewObj will now be an object of the same Type as the anonymous type.
The language feature you need is:
public var GetMe()
{
return new { FirstName = "John", LastName = "Smith" };
}
That is, var would be valid as a method return type, and the compiler would infer the actual type from whatever is returned. You would then have to do this at the call site:
var me = GetMe();
Any two anonymous types with members of the same type would be the same type, so if you wrote other functions returning the same pattern, they would have the same type. For any types A and B where B has a subset of the members of A, then A is assignment-compatible with B (B is like a base class of A). If you wrote:
public var GetMeFrom(var names)
{
return new { FirstName = names["First"], LastName = names["Last"] };
}
The compiler would effectively define this as a generic method with two type parameters, T1 being the type of names and T2 being the type returned by the indexer on T1 that accepts a string. T1 would be constrained so that it must have an indexer that accepts a string. And at the call site you would just pass anything that had an indexer that accepted a string and returned any type you like, and that would determine the type of FirstName and LastName in the type returned by GetMeFrom.
So type inference would figure all this out for you, automatically capturing whatever type constraints are discoverable from the code.
IMHO the root problem is nothing to do with anonymous types, but that declaring a class is too verbose.
Option 1:
If you could declare a class like this:
public class MyClass
{ properties={ int Number, int Square, int Absolute, IEnumerable<int> Range } }
or some other similarly quick way (like the tuple example) then you wouldn't feel the need to do hacky things with anonymous types just to save some code.
When 'compiler as a service' arrives in C#5, hopefully they'll do a good job of integrating it and we'll be able to use metaprogramming to solve these kinds of problems cleanly. Party like it's 1958!
Option 2:
Alternatively, in C#4, you could just pass an anonymous type around as dynamic and avoid all the casting. Of course this opens you up to runtime errors if you rename a variable, etc.
Option 3:
If C# would implement generics in the same way as C++, then you could pass the anonymous type into a method, and so long as it had the right members, it would just compile. You'd get all the benefits of static type safety, and none of the downsides. Every time I have to type where T : ISomething in C# I get annoyed that they didn't do this!
What you are describing (named anonymous types) are basically "tuple types".
I think they would be a nice addition to C#.
If I were designing such a feature for C#, I would expose it using syntax like this:
tuple<int x, int y>
so that you could do:
public tuple<int x, int y> GetStuff()
{
}
I would then change the definition of anonymous types, so that:
new { x = 2, y = 2}
had tuple<int x, int y> as it's type, rather than an anonymous type.
Getting this to work with the current CLR is a little tricky, because once you can name an anonymous type in public signatures you need to be able to unify them across separately compiled assemblies. It can be accomplished by embedding a "module constructor" inside any assembly that uses a tuple type. See this post for an example.
The only downside to that approach is that it doesn't respect the CLR's "lazy" model for type generation. That means that assemblies that use many distinct tuple types might experience slightly slower load types. A better approach would be to add support for tuple types directly to the CLR.
But, apart from changing the CLR, I think the module constructor approach is the best way of doing something like this.
I would love this feature, there have been many times I've wanted this.
A good example is processing XML. You parse them get back an object, but then you need to make a concrete version of the object to send back to a caller. Many times you get XML that changes quite considerably and requires you make many classes to handle it. Wouldn't it be wonderful if you could just build the object using LinqToXml as a var, then just return that?
I think this would be a nice compiler magic for tuples:
Creating a tuple:
(int, string, Person) tuple = (8, "hello", new Person());
equivalent to:
Tuple<int,string,Person> tuple = new Tuple<int,string,Person>(8 ,"hello", new Person());
In a function:
public (int, string, Person) GetTuple(){
return ...
}
Getting values:
int number = tuple[1];
string text = tuple[2];
Person person = tuple[3];
Could you create an Interface with the properties FirstName and LastName and use that?