Using an Anonymous method to populate a property in an object initializer - c#

Assuming sr is an IEnumerable<string>, I want to use code like this to do an inline calculation using two of the items from sr.Lines(). The problem is that the lambda is of type "lambda expression" and not a Decimal, which shares is expecting. Is there any way to do this type of inline method in an object initializer?
var trades =
from line in sr.Lines()
let items = line.Split('|')
select new Trade
{
Total = () => {
return Convert.ToDecimal(items[1]) + Convert.ToDecimal(items[2]);
},
Name = items[3]
}

You want a decimal expression, not a function:
var trades =
from line in sr.Lines()
let items = line.Split('|')
select new Trade
{
Total = Convert.ToDecimal(items[1]) + Convert.ToDecimal(items[2]),
Name = items[3]
};

Just in case someone else ends up here looking for a solution like I did.
Check How to call anonymous function in C#?.
var trades =
from line in sr.Lines()
let items = line.Split('|')
select new Trade
{
Total = ((Func<decimal>)(() =>
{
return Convert.ToDecimal(items[1]) + Convert.ToDecimal(items[2]);
}))(),
Name = items[3]
};

Related

Querying a list of strings with a query string?

I have a dictionary:
<string,List<string>>
The key is the product code say "product1" then the list is a list of properties:
"Brand","10.40","64","red","S"
Then I 'can' have a list of rules/filters e.g.
var tmpFilter = new customfilters();
tmpFilter.Field = "2";
tmpFilter.Expression = ">";
tmpFilter.Filter = "10";
So for the above example this would pass because at index 2 (tmpFilter.Field) it is more than 10; then I have another object which defines which fields within the list I want to write to file. For that dictionary item I just want to write the product brand and price where the filters match.
At the moment without the filter I have:
var tmp = new custom();
tmp.Columns = "0,1";
tmp.Delimiter = ",";
tmp.Extention = ".csv";
tmp.CustomFilters = new List<customfilters>() {new customfilters(){ Field = "2", Expression = ">", Filter = "10"} };
public static void Custom(custom custom)
{
foreach (var x in Settings.Prods)
{
//Get Current Product Code
var curprod = Settings.ProductInformation[x];// the dictionary value
foreach (var column in custom.Columns)
{
var curVal = curprod[Convert.ToInt32(column)];
tsw.Write(curVal + custom.Delimiter);
}
Settings.Lines++;
tsw.WriteLine();
}
tsw.Close();
}
I only want to write the curprod if all the filters pass for that list of strings.
How I can do this?
There's a really nice Nuget package based on an example published by Microsoft, that they have decided to make really hard to find for some reason, that allows dynamic linq queries:
https://www.nuget.org/packages/System.Linq.Dynamic/1.0.2
Source:
https://github.com/kahanu/System.Linq.Dynamic
Using that you can do stuff like this very easily (note: I used strings here because the OP states they have a List<string>):
List<string> stuff = new List<string> { "10.40", "64", "5", "56", "99", "2" };
var selected = stuff.Select(s => new { d = double.Parse(s) }).Where("d > 10");
Console.WriteLine(string.Join(", ", selected.Select(s => s.d.ToString()).ToArray()));
Outputs:
10.4, 64, 56, 99
That may give you a place to start. One thing you are going to have to tackle is identifying which of your fields are numeric and should be converted to a numeric type before trying to apply your filter. Otherwise you are going to comparing as strings.

Building a Dynamic Linq Query using Equals and an Array

I have been trying to solve the syntax for a dynamic linq query that is needed in my application.
I have a dynamic query that the where clause needs to be specified to either
GuidPrimaryKey is contained in a list of Guid OR
GuidPrimaryKey is equal to an item in a list of Guid (using some type of for-loop)
I have a Guid[] populated with over 5,000 keys. My Query is set up as
If I do this (as a test) it is successful
data = data.where("GuidPrimaryKey.Equals(#0)",array[0]);
as well as
data = data.where("GuidPrimaryKey.Equals(#0) OR GuidPrimaryKey.Equals(#1)",array[0], array[1]);
I have tried:data = data.where("GuidPrimaryKey.Contains(#0)",array); but that gives an error: No applicable method 'Contains' exists in type 'Guid'.
I also tried setting a loop to go through the elements in the array and set the where clause as a giant string, but that did not work either.
string s = "";
string p = ""
int counter = 0;
foreach(Guid g in Array)
{
s+= "GuidPrimaryKey.Equals(#" counter.ToString() + ") OR";
p += "Array[" counter.ToString() + "],";
counter++;
}
s = s.remove(s.length - 3, 3);
p = p.remove(p.length - 1, 1);
data = data.Where(s,p);
This gives me the error message: No Property or field '1' exists in type 'DynamicClass1'
Any ideas? I need to have the where clause build the query to check to see if the primary key (GuidPrimaryKey) exists in the list of keys (Guid[]).
I'm not sure if this works in the standard Dynamic Linq library, but I just tried this is my open-source version, and it works well:
var data = data.Where("GuidPrimaryKey in #0", array);
This also works:
var data = data.Where("#0.Contains(GuidPrimaryKey)", array);
Here is a full unit test I wrote to confirm this:
[TestMethod]
public void ExpressionTests_ContainsGuid()
{
//Arrange
//Generate some users with Id fields of type Guid
var userList = User.GenerateSampleModels(5, false);
var userQry = userList.AsQueryable();
//Generate a list of values that will fail.
var failValues = new List<Guid>() {
new Guid("{22222222-7651-4045-962A-3D44DEE71398}"),
new Guid("{33333333-8F80-4497-9125-C96DEE23037D}"),
new Guid("{44444444-E32D-4DE1-8F1C-A144C2B0424D}")
};
//Add a valid Guid so that this list will succeed.
var successValues = failValues.Concat(new[] { userList[0].Id }).ToArray();
//Act
var found1 = userQry.Where("Id in #0", successValues);
var found2 = userQry.Where("#0.Contains(Id)", successValues);
var notFound1 = userQry.Where("Id in #0", failValues);
var notFound2 = userQry.Where("#0.Contains(Id)", failValues);
//Assert
Assert.AreEqual(userList[0].Id, found1.Single().Id);
Assert.AreEqual(userList[0].Id, found2.Single().Id);
Assert.IsFalse(notFound1.Any());
Assert.IsFalse(notFound2.Any());
}

where clause in LINQ to Entites DataBind

I'm trying to add a where clause to an existing LINQ DataBind but nothing I do works. The where clause I want to add checks if in the table refAuthSigner the column IsActive == 1.
Here's my existing Query:
// populates Authorized Signer dropdownlist
using (dbPSREntities10 myEntities = new dbPSREntities10())
{
var allSigners = from refAuthSigner in myEntities.refAuthSigners <--- where clause somewhere around here??
select new
{
refAuthSignerID = refAuthSigner.refAuthSignerID,
refAuthSignerName = refAuthSigner.refAuthSignerFirst + " " + refAuthSigner.refAuthSignerLast
};
ddlAuthSigners.DataSource = allSigners;
ddlAuthSigners.DataValueField = "refAuthSignerID";
ddlAuthSigners.DataTextField = "refAuthSignerName";
ddlAuthSigners.DataBind();
}
I want to add a where clause which is something like:
var allSigners = from refAuthSigner in myEntities.refAuthSigners
where refAuthSigner.IsActive == 1
This code isn't right and just wondering how I would incorporate the where clause into the code. Thanks!
Simply use:
where refAuthSigner.IsActive
Since it's a boolean value you cannot compare it to an integer. It is true or false, not 1 or 0. (Some langauges conflate the two, C# is not one of them.)
There is no need to compare IsActive to anything. where needs a boolean value, and IsActive is a boolean value. You already have exactly what you need.
You could make the statement:
var allsigners = refAuthSigner.Where(x => x.refAuthSigner.IsActive)
Try this:
var allSigners = from refAuthSigner in myEntities.refAuthSigners
where refAuthSigner.IsActive
select new
{
refAuthSignerID = refAuthSigner.refAuthSignerID,
refAuthSignerName = refAuthSigner.refAuthSignerFirst + " " + refAuthSigner.refAuthSignerLast
};
Operator of '==' cannot be applied to operands of type 'bool' and 'int'. IsActive is type bit in SqlServer
If this is the error you are getting try using Any instead of Where as it returns bool
// populates Authorized Signer dropdownlist
using (dbPSREntities10 myEntities = new dbPSREntities10())
{
var allSigners = from refAuthSigner in myEntities.refAuthSigners
where refAuthSigner.IsActive
select new
{
refAuthSignerID = refAuthSigner.refAuthSignerID,
refAuthSignerName = refAuthSigner.refAuthSignerFirst + " " + refAuthSigner.refAuthSignerLast
};
ddlAuthSigners.DataSource = allSigners;
ddlAuthSigners.DataValueField = "refAuthSignerID";
ddlAuthSigners.DataTextField = "refAuthSignerName";
ddlAuthSigners.DataBind();
}

Concat not working - The underlying array is null

I am trying to Concat the two array IEnumerable lists and in result view it says The underlying array is null.
IEnumerable<ObjectToConcat> result = new ArraySegment<ObjectToConcat>();
var listA = new List<ObjectToConcat>();
var a = new ObjectToConcat
{OfficialId = Guid.NewGuid(), FirstName = "A Object"};
listA.Add(a);
var b = new ObjectToConcat
{OfficialId = Guid.NewGuid(), FirstName = "B Object"};
listA.Add(b);
// Error here is result view
result = result.Concat(listA);
var c = new ObjectToConcat
{OfficialId = Guid.NewGuid(), FirstName = "C Object"};
listB.Add(c);
// Error here is result view
result = result.Concat(listB);
Can anyone please suggest me what is wrong with my code. Or Concat does not work with List?
It would appear that this code:
IEnumerable<ObjectToConcat> result = new ArraySegment<ObjectToConcat>();
is an attempt to make an empty enumerable. You can do this more effectively and clearly by writing:
IEnumerable<ObjectToConcat> result = Enumerable.Empty<ObjectToConcat>();
That said, chaining a lot of Concat calls probably isn't the most effective, performance wise, if there are a lot of sub-lists. It's probably going to perform a bit better if you create a List<IEnumerable<ObjecToConcat>> allLists, add all of the sub-lists to that list, and then at the end you can write:
result = allLists.SelectMany(x => x);
to flatten it down to just a list of items.
you can have list of ObjectToConcat like below and add items to it using addrange method
List<ObjectToConcat> result = new List<ObjectToConcat>();
result.AddRange(listA);
Try this:
IEnumerable<ObjectToConcat> result =
new ArraySegment<ObjectToConcat>(new ObjectToConcat[0]).Array;

LINQ and creating NON anonymous return values

I think I understand returning records of an anonymous type from But in this I want to create NEW CatalogEntries, and set them from the values selected. (context is a Devart LinqConnect database context, which lets me grab a view).
My solution works, but it seems clumsy. I want to do this in one from statement.
var query = from it in context.Viewbostons
select it;
foreach (GPLContext.Viewboston item in query)
{
CatalogEntry card = new CatalogEntry();
card.idx = item.Idx;
card.product = item.Product;
card.size = (long)item.SizeBytes;
card.date = item.Date.ToString();
card.type = item.Type;
card.classification = item.Classification;
card.distributor = item.Distributor;
card.egplDate = item.EgplDate.ToString();
card.classificationVal = (int)item.ClassificationInt;
card.handling = item.Handling;
card.creator = item.Creator;
card.datum = item.Datum;
card.elevation = (int)item.ElevationFt;
card.description = item.Description;
card.dirLocation = item.DoLocation;
card.bbox = item.Bbox;
card.uniqID = item.UniqId;
values.Add(card);
}
CatalogResults response = new CatalogResults();
I just tried this:
var query2 = from item in context.Viewbostons
select new CatalogResults
{ item.Idx,
item.Product,
(long)item.SizeBytes,
item.Date.ToString(),
item.Type,
item.Classification,
item.Distributor,
item.EgplDate.ToString(),
(int)item.ClassificationInt,
item.Handling,
item.Creator,
item.Datum,
(int)item.ElevationFt,
item.Description,
item.DoLocation,
item.Bbox,
item.UniqId
};
But I get the following error:
Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a
collection initializer because it does not implement
'System.Collections.IEnumerable' C:\Users\ysg4206\Documents\Visual
Studio
2010\Projects\CatalogService\CatalogService\CatalogService.svc.cs 91 25 CatalogService
I should tell you what the definition of the CatalogResults is that I want to return:
[DataContract]
public class CatalogResults
{
CatalogEntry[] _results;
[DataMember]
public CatalogEntry[] results
{
get { return _results; }
set { _results = value; }
}
}
My mind is dull today, apologies to all. You are being helpful. The end result is going to be serialized by WCF to a JSON structure, I need the array wrapped in a object with some information about size, etc.
Since .NET 3.0 you can use object initializer like shown below:
var catalogResults = new CatalogResults
{
results = context.Viewbostons
.Select(it => new CatalogEntry
{
idx = it.Idx,
product = it.Product,
...
})
.ToArray()
};
So if this is only one place where you are using CatalogEntry property setters - make all properties read-only so CatalogEntry will be immutable.
MSDN, Object initializer:
Object initializers let you assign values to any accessible fields or properties of an
object at creation time without having to explicitly invoke a constructor.
The trick here is to create a IQueryable, and then take the FirstOrDefault() value as your response (if you want a single response) or ToArray() (if you want an array). The error you are getting (Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a collection initializer because it does not implement 'System.Collections.IEnumerable') is because you're trying to create an IEnumerable within the CatalogEntry object (by referencing the item variable).
var response = (from item in context.Viewbostons
select new CatalogEntry()
{
idx = item.Idx,
product = item.Product,
size = (long)item.SizeBytes,
...
}).ToArray();
You don't have to create anonymous types in a Linq select. You can specify your real type.
var query = context.Viewbostons.Select( it =>
new CatalogEntry
{
idx = it.idx,
... etc
});
This should work:
var query = from it in context.Viewbostons
select new CatalogEntry()
{
// ...
};

Categories