Error when trying to cast anonymous object, Razor - c#

I am trying to cast an array of anonymous objects, where each object looks like this:
new {type="internal",title="Linktitle",target="_blank",link="http://www.google.se"}
I have declared a Class "Link", to which the anonymous objects should be casted
class Link{
public string type {get;set;}
public string target {get;set;}
public string title {get;set;}
public string link {get;set;}
}
Now i am trying to cast the objects, like this
List<Link> links = Model.relatedLinks.Select(l => new Link{type=l.type,target=l.target,title=l.title,link=l.link}).ToList();
Then i get the error
Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type
I found this page on how to cast anonymous objects, but im doing it the same way. Or have i missed something?

If relatedLinks itself is a dynamic value, you've got two problems:
The lambda expression part as already reported
Extension methods can't be called on dynamic values (as extension methods). This affects both the Select and ToList methods.
You can work round the first by casting the lambda expression. You can work round the second by calling Enumerable.Select directly:
// Note: don't use var here. We need the implicit conversion from
// dynamic
IEnumerable<Link> query = Enumerable.Select(Model.relatedLinks,
(Func<dynamic, Link>) (l => new Link {
type = l.type,
target = l.target,
title = l.title,
link = l.link } );
var links = query.ToList();
Or for the sake of formatting:
Func<dynamic, Link> projection = l => new Link {
type = l.type,
target = l.target,
title = l.title,
link = l.link };
IEnumerable<Link> query = Enumerable.Select(Model.relatedLinks, projection);
var links = query.ToList();
If Model.relatedLinks is already IEnumerable<dynamic> (or something similar) then you can call Select as an extension method instead - but you still need to have a strongly-typed delegate. So for example, the latter version would become:
Func<dynamic, Link> projection = l => new Link {
type = l.type,
target = l.target,
title = l.title,
link = l.link };
IEnumerable<Link> query = Model.relatedLinks.Select(projection);
var links = query.ToList();

Related

How to get the Id of the selectedvalue?

I have DropDownList with the following values:
ddl.SelectedValue = { Id = 234, Name = "ABC Name" }
How can I get the value of the Id?
I use WinForms and RadDropDownList
Try this one:
public int GetId(object obj)
{
var anon = new { Id = 0, Name = string.Empty };
var obj2 = MakeSameType(obj, anon);
return obj2.Id;
}
public static T MakeSameType<T>(object obj, T anonymous)
{
return (T)obj;
}
use it like:
int id = GetId(ddl.SelectedValue);
If it works, it is thanks to how the equivalent anonymous types are "condensed" in single types by the C# compiler.
Note that this solution is as brittle as you can have
If you add/remove/rename a property of the anonymous type, the GetId will break (you'll have to keep the var anon = new {...} perfectly aligned). If you move the method that creates the collection of anonymous types to another assembly it will break too (because only anonymous types inside the same assembly are "unified" by the compiler).
In general you shouldn't have anonymous types that "escape" a method. An anonymous type should remain in the method that it is defined. Assigning it directly as the DataSource of a control is asking for problems.
If you feel lazy and don't want to create a type for a key-value, use the Tuple:
var tuple = Tuple.Create(something, somethingelse, somethingstillelse);
var value1 = tuple.Item1;
var value2 = tuple.Item2;
var value3 = tuple.Item3;
and so on.
As your are using anonymous types, it gets little complicated. But, you can cast SelectedValue to dynamic, and exstract 'Id' from there:
dynamic selectedValue = ddl.SelectedValue;
int id = selectedValue.Id;
But i would recommend to declare your own class or struct for such cases.
I have changed the LINQ query
from:
var query = (from q in tableq where ...
select new {Id = q.Id, Name = q.Name});
to:
var query = (from q in tableq where ...
select q);
... and then change it to:
table1.Id = (ddl.SelectedValue as tableq).Id == null ? table1.Id : (ddl.SelectedValue as tableq).Id;

Syntax to refer a method returning an Expression to another method?

I found a piece of code of the following form:
public static Expression<Func<Invoice, CustomerContact>> GetCustomerContact()
{
return i => new CustomerContact {
FirstName = i.Customer.FirstName,
LastName = i.Customer.LastName,
Email = i.Customer.Email,
TelMobile = i.Customer.TelMobile,
};
}
In other parts of the code, I want to get the same lightweight CustomerContact object, only not from the Invoice, but from the Customer itself. So the obvious thing to do would be to have:
public static Expression<Func<Customer, CustomerContact>> GetCustomerContact()
{
return c => new CustomerContact {
FirstName = c.FirstName,
LastName = c.LastName,
Email = c.Email,
TelMobile = c.TelMobile,
};
}
and then change the Expression taking Invoice as input to refer to this method, i.e. something like this:
public static Expression<Func<Invoice, CustomerContact>> GetCustomerContact()
{
return i => GetCustomerContact(i.Customer); // doesn't compile
}
What's the correct syntax for this?
You can use Expression.Invoke:
var paramExpr = Expression.Parameter(typeof(Invoice), "i");
var propertyEx = Expression.Property(paramExpr, "Customer");
var body = Expression.Invoke(GetCustomerContactFromCustomer(), propertyEx);
return Expression.Lambda<Func<Invoice, CustomerContact>>(body, paramExpr);
Do note that some LINQ providers have problems with such invocation-expressions.
The easiest way to work around this (and to give you more convenient syntax) is to use LINQKit:
var expr = GetCustomerContactFromCustomer();
Expression<Func<Invoice, CustomerContact>> result = i => expr.Invoke(i.Customer);
return result.Expand();
Are you sure you need to use an Expression? If you don't need different Linq providers to convert code trees into queries, then consider using just Func, instead. If you just use Func so that the method signatures are:
public static Func<Customer, CustomerContact> GetCustomerContact();
and
public static Func<Customer, CustomerContact> GetCustomerContact();
Then your syntax would be fine for constructing the second Func off of the first one. Of course, this will only work for in-memory objects (with Linq-to-objects).
The problem is that in order to build an Expression, you have to explicitely build the evaluation tree, which can be quite hairy (using the various static methods on Expression). Because of this hairiness, there are several helper packages, including LINQKit.

How to use Expression.MakeIndex in Linq Expressions?

Property indexer array
trying to dynamically generate the following lambda expression:
Expression<Func<Program, string>> y = _ => _.x[0];
Where x is of type List
Attempting to use Expression.MakeIndex, but it seems to be bouncing an exception:
Expression.MakeIndex(parameter, typeof (Program).GetProperty("x"), new[] {Expression.Constant(0)})
The exception message:
Incorrect number of arguments supplied for call to method
'System.Collections.Generic.List`1[System.String] get_x()'
How can I make this right?
There are two operations going on here:
Get x from parameter
Access item at index 0
You need to create two separate expressions for this:
var property = Expression.Property(parameter, typeof (Program).GetProperty("x"));
var itemAtPosition0 = Expression.MakeIndex(property, typeof(List<string>).GetProperty("Item"),
new [] { Expression.Constant(0) });
"Item" refers to the default name of the indexer property. For more information about this name and how to reliably detect the actual name used, have a look at this answer.
This answer assumes that the Program class is defined like this:
public class ProgramZ
{
public List<string> x { get; set; }
}
The problem is that you are trying to applying the indexing to the Program.x property, when it really should be applied to the List<string>'s indexer property (which is called Item).
In the end, to be able to Invoke the expression you need to wrap it into a lambda.
Here's the code to do that:
var expr =
Expression.Lambda<Func<Program, string>>(
Expression.MakeIndex(
Expression.Property(
parameter,
typeof(Program).GetProperty("x")),
typeof(List<string>).GetProperty("Item"),
new[] { Expression.Constant(0) }),
parameter);
And here's how to invoke the expression:
var instance = new ProgramZ { x = new List<string> { "a", "b" } };
Console.WriteLine(expr.Compile().Invoke(instance));
This code will output a, as expected.

Dynamic LINQ: Specifying class name in new clause

With Dynamic LINQ, what changes need to be done to have fields of the given class?
For example, how can the following C# query be reproduced in DLinq:
var carsPartial = cars.Select(c => new {c.year, c.name, make = new maker() {name = c.make.name} }).ToList();
I have applied the changes mentioned in this answer https://stackoverflow.com/a/1468357/288747 to allow the return type to be the calling type rather than an anonymous type.
With the class definition is as follows (if it helps):
class car
{
public int vid;
public int odo;
public int year;
public string name;
public maker make;
}
class maker
{
public string name;
public int firstYear;
}
The following doesn't work (but I think is close, but still doesn't work as I don't have the changes necessary to the dynamic linq library, which is what I need):
var carsPartial = cars.Select("new(name, year, new maker() {name = make.name})").ToList();
But it fails at the new maker() { (as expected).
I'm sure I need to change the DynamicLibrary.cs to get this working and could do with some direction on how to alter it to achieve this.
UPDATE: I have turned my answer into a little bit more extensive blog post.
I have not really ever used Dynamic Linq library, but I have taken a look at the DynamicLibrary.cs code and the change to support generating type classes provided in another stackoverflow question you provided link to in your question. Analyzing them all, it seems that the nested new-s should work out of the box in your configuration.
However, it seems your query is not the correct Dynamic Linq's language query. Note, that the query string for DLinq is not equivalent to C# and has its own grammar.
The query should read out, I believe, the following:
var carsPartial = cars.Select("new(name, year, new maker(make.name as name) as make)").ToList();
EDIT:
Rereading this stackoverflow question more carefully, I realizes, that it actually does not extend the Dynamic Linq's language with the possibility for creating new strong-typed classes. They just put the result to the class specified as a generic parameter of Select() instead of specifying it in the query string.
To obtain what you need you will need to revert their changes (get generic DLinq) and apply my changes, I have just verified to work:
Locate the ParseNew method of ExpressionParser class and change it to the following:
Expression ParseNew() {
NextToken();
bool anonymous = true;
Type class_type = null;
if (token.id == TokenId.Identifier)
{
anonymous = false;
StringBuilder full_type_name = new StringBuilder(GetIdentifier());
NextToken();
while (token.id == TokenId.Dot)
{
NextToken();
ValidateToken(TokenId.Identifier, Res.IdentifierExpected);
full_type_name.Append(".");
full_type_name.Append(GetIdentifier());
NextToken();
}
class_type = Type.GetType(full_type_name.ToString(), false);
if (class_type == null)
throw ParseError(Res.TypeNotFound, full_type_name.ToString());
}
ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
NextToken();
List<DynamicProperty> properties = new List<DynamicProperty>();
List<Expression> expressions = new List<Expression>();
while (true) {
int exprPos = token.pos;
Expression expr = ParseExpression();
string propName;
if (TokenIdentifierIs("as")) {
NextToken();
propName = GetIdentifier();
NextToken();
}
else {
MemberExpression me = expr as MemberExpression;
if (me == null) throw ParseError(exprPos, Res.MissingAsClause);
propName = me.Member.Name;
}
expressions.Add(expr);
properties.Add(new DynamicProperty(propName, expr.Type));
if (token.id != TokenId.Comma) break;
NextToken();
}
ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
NextToken();
Type type = anonymous ? DynamicExpression.CreateClass(properties) : class_type;
MemberBinding[] bindings = new MemberBinding[properties.Count];
for (int i = 0; i < bindings.Length; i++)
bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
return Expression.MemberInit(Expression.New(type), bindings);
}
Then, find the class Res and add the following error message:
public const string TypeNotFound = "Type {0} not found";
Et voilĂ , you will be able to construct queries like:
var carsPartial = cars.Select("new(name, year, (new your_namespace.maker(make.name as name)) as make)").ToList();
Make sure, you include the full type name including the whole namespace+class path.
To explain my change, it just checks if there is some identifier between new and opening parenthesis (see the added "if" at the begging). If so we parse full dot-separated class name and try to get its Type through Type.GetType instead of constructing own class in case of anonymous news.
If I've understood you correctly you want to make a plain anonymous class that contains fields from both class car and class maker. If it's the case you can just provide new names in that class, something like the following:
var carsPartial = cars.Select(c => new { year = c.year, name = c.name, make_name = c.make.name });
Or even provide names only to conflicting fields:
var carsPartial = cars.Select(c => new { c.year, c.name, make_name = c.make.name });

LINQ Guid toString()

Hi this seems like it should work,
from something in collectionofsomestuff
select new SelectListItem(){Text = something.Name, Value = something.SomeGuid.ToString(), Selected = false};
When I try to do this it doesn't work give me error
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
Is there a workaround?
Not all CLR methods can be used with Linq-to-Entities. ToString() seems to be one of them.
Take a look at CLR Method to Canonical Function Mapping.
Maybe try setting the GUID to a string variable explicitly, outside of Linq.
string myGuid = SomeGuid.ToString();
from something in collectionofsomestuff
select new SelectListItem(){Text = Name, Value = myGuid, Selected = false};
You can get the records in the db,and then turn them to a list or a array use ToList() or ToArray().Then use the object.
For example(it is LINQ to Entities ):
var list = collectionofsomestuff.select(c => c).ToList();
from something in list
select new SelectListItem(){Text = something.Name, Value = something.SomeGuid.ToString(), Selected = false};
I don't speak Linq query expressions too well, but the following should do the trick:
collectionofsomestuff //here it's LinqToEntities
.Select(something=>new{something.Name,something.SomeGuid})
.ToArray() //From here on it's LinqToObjects
.Select(s=>new SelectListItem()
{
Text = s.Name,
Value = s.SomeGuid.ToString(),
Selected = false
})
I ended up doing a foreach like so
List<SelectListItem> list = new List<SelectListItem>();
foreach (SomeThing something in collectionofsomestuff)
{
list.Add(new SelectListItem(){Text = something.Name,Selected = false,Value = something.SomeGuid.ToString()});
}
this is the only way I could get it to work..it wasn't what i was hoping to do tough..
Create a constructor for SelectListItem that accepts your Value as a Guid and ToString it there. Now call your query like so:
from something in collectionofsomestuff select new SelectListItem(something.Name, something.SomeGuid, false);
I had the same problem, and I ended up changing my object's definition to get around the problem. It's a complete hack, but it allows me to populate the data straight from the query:
[DataContract]
public class DeviceInfo
{
public Guid DeviceGuid
{
set
{
DeviceID = value.ToString();
}
}
[DataMember]
public string DeviceID { get; set; }
}
And the query works as designed because it has something else doing the conversion for it:
devices.AddRange(from d in ae.UserDevices
select new DeviceInfo
{
DeviceGuid = d.DeviceID
}
It makes the object a little messier, but makes dealing with the Guid in the query so much easier.

Categories

Resources