Is it possible to extend the Query-Keywords in C# / LINQ? - c#

is it possible to extend the query-keywords of Linq (like: select, where, etc.) with own definitions?
Codeexample to make it clearer:
System.Collections.Generic.List<string> aList =
new System.Collections.Generic.List<string> { "aa", "ab", "ba", "bb" };
// instead of
string firstString = (from item in aList
where item.StartsWith("a")
select item).First();
// would be nice
string firstString = from item in aList
where item.StartsWith("a")
selectFirst item;
// or something else
from item in aList
where item.StartsWith("a")
WriteLineToConsole item;
I think it's not possible, but still hoping ;)

You can't add your own contextual keywords, but you can affect what the existing ones mean.
For example, this code:
string firstString = (from item in aList
where item.StartsWith("a")
select item).First();
is effectively preprocessed to:
string firstString = aList.Where(item => item.StartsWith("a"))
.First();
... so if you change what those Where and First method calls mean, you can affect the behaviour.
If you've got the stomach for it, you might want to look at this Stack Overflow answer I wrote a while ago which changes the behaviour of where in LINQ to Entities in certain circumstances. It's evil, evil code though.

One way to achieve this would be to write a pre-processor which will transform your custom LINQ keywords into standard LINQ keywords before feeding it to the compiler. By the way that's how it works with the standard LINQ keywords. A pre-processor converts them into normal extension methods (.Select, .Where, .GroupBy, ...), and then feeds it to the compiler which doesn't understand those keywords.
Of course by doing this you will lose Intellisense, but this could be solved by writing a Visual Studio extension. Could be quite a lot of work though for this sugar.

No, it is not possible within the language spec or any current C# compiler. Anything you create there would no longer be (pure) C#.

Related

Build regular expression for replacing duplicated string into single word

I'm working of filtering comments. I'd like to replace string like this:
llllolllllllllllooooooooooooouuuuuuuuuuuddddddddddddddllllollllllllllllloooooooooooooooooouuuuuuuuuuuuuuuuuuddddddddddddddllllollllllllllllloooooooooooooooooouuuuuuuuuuuuuuuuuuddddddddddddddllllollllllllllllloooooooooooouuuuuuuuuuuuuuuuudddddddddddddd
with two words: lol loud
string like this:
cuytwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
with: cuytw
And string like this:
hyyuyuyuyuyuyuyuyuyuyuyuyuyu
with: hyu
but not modify strings like look, geek.
Is there any way to achieve this with single regular expression in C#?
I think I can answer this categorically.
This definitely cant be done with RegEx or even standard code due to your input and output requirements without at minimum some sort of dictionary and algorithm to try and reduce doubles in a permutation check for legitimate words.
The result (at best) would give you a list of possible non mutually-exclusive combinations of nonsense words and legitimate words with doubles.
In fact, I'd go as far to say with your current requirements and no extra specificity on rules, your input and output are generically impossible and could only be taken at face value for the cases you have given.
I'm not sure how to use RegEx for this problem, but here is an alternative which is arguably easier to read.*
Assuming you just want to return a string comprising the distinct letters of the input in order, you can use GroupBy:
private static string filterString(string input)
{
var groups = input.GroupBy(c => c);
var output = new string(groups.Select(g => g.Key).ToArray());
return output;
}
Passes:
Returns loud for llllolllllllllllooooooooooooouuuuuuuuuuuddddddddddddddllllollllllllllllloooooooooooooooooouuuuuuuuuuuuuuuuuuddddddddddddddllllollllllllllllloooooooooooooooooouuuuuuuuuuuuuuuuuuddddddddddddddllllollllllllllllloooooooooooouuuuuuuuuuuuuuuuudddddddddddddd
Returns cuytw for cuytwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
Returns hyu for hyyuyuyuyuyuyuyuyuyuyuyuyuyu
Failures:
Returns lok for look
Returns gek for geek
* On second read you want to leave words like look and geek alone; this is a partial answer.

How To Add Items From a ComboBox to a List Collection

I've got a combo box with a few strings. I would like to add those string to a List collection. Is this the correct way of doing it?
List<string> comboItems = new List<string>();
foreach(string passItems in comboEmail.Items)
{
comboItems.Add(passItems);
}
A slightly different way:
List<string> comboItems = comboEmail.Items.Cast<string>().ToList();
That is a perfectly valid approach.
You can also cast to string and use AddRange to create a one-liner.
comboItems.AddRange(cb.comboEmail.Cast<string>());
Your approach is simple enough. Use it.
Sometimes simple foreach statement with one line code inside
will be more readable then nice looking one line LINQ code.
Anyway both versions will be doing almost same work. LINQ can be even slowly then foreach

Return filtered String[] from String[] using Linq

Sorry if this has been answered - I have read at least 20 questions that answer an almost identical question but they're all with slightly different circumstances or I can't get them to work.
That's also despite the fact what I want is far more simple! :(
All I want to do is return all the elements of a string array that start with "ABC".
So {"ABC_1", "ABC_2", "ABC_3", "123_1", "ABC_4"}
Will return {"ABC_1", "ABC_2", "ABC_3", "ABC_4"}
Using Linq with Lambda Expressions:
So the logic would be similar to the following:
FilteredArray = StringArray.Where(String.StartsWith("ABC"));
Everytime I try something similar to the above it returns no values.
Thank you in advanced for your help and apologies in advanced for not being able to solve this independently.
P.S If you know of a link that would provide me with a good tutorial on Linq with Lambda Expressions that would be greatly appreciated.
If you want to make an array from an array, you need to use ToArray. You also need to get your LINQ syntax right:
// This assumes that FilteredArray is declared as String[]
FilteredArray = StringArray.Where(str => str.StartsWith("ABC")).ToArray();
Note that Where is not all-caps because identifiers in C# are case-sensitive. Also note the use of the lambda syntax inside the Where method.
I'm not actually sure the original example would compile? Your missing the lambda syntax. This will work correctly. Basically you need to specify the input parameter for the where clause (each of the strings in the array) this is x. Then you do you're string startswith check on that.
var filtered = StringArray.Where(x => x.StartsWith("ABC"));
You need to use the correct syntax in your lambda expression like this
var FilteredArray = StringArray.Where(x => x.StartsWith("ABC")).ToArray();
If you want to learn about Linq expressions then here is a very good solution available for you 101 Linq Samples

How to convert a search string to a boolean condition?

I have a search criteria stored in a string:
string Searchstr = "(r.Value.Contains("PwC") || (r.Value.Contains("Canadian") && r.Value.Contains("thrive"))) || (r.Value.Contains("Banana") && r.Value.Contains("Gayle"))"
I want to use this in a If statement to check the values:
if(searchstr)
{
then do this....
}
but the if should have a searchstr as boolean.
How to convert this to boolean?
EDIT: The requirement is to give search criteria dynamically in a text box in the following format - "PwC OR (Canadian AND thrive)".
Which will be used to search an XML file.
Therefore I have loaded an XML file and want to have a Where condition in LINQ for which I need to use Dynamic LINQ but string is not allowed in that and also I have some braces to deal with.
Thinking of that I have taken the resultset from the XML(The tag value which i need to search)
var selectedBook = from r in document.Root.Descendants("Archives").Elements("Headline").Elements("Para")
select r;
and would ideally like to try something like:
var query=selectedbook.Where(searchstr)
OR
if(searchstr){....then do this}
You will need to do a bit of work to make this happen, but it is possible.
You should have a look at the dynamic LINQ library. This allows you to specify LINQ conditions (and other clauses) as strings and execute them just like LINQ operators.
Start with the explanation on ScottGu's blog and follow the links:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
I'm assuming the string is going to reference only a specific set of objects (r or r.Value in this case, for example - or anything else you want, as long as you know it beforehand). If this is the case, then:
Create a delegate that takes the objects (that may be referenced) as parameters
and returns a bool, as you want.
Programmatically write a small C# source file in memory that defines the query
as the body of a method (with a fixed name, preferably) that conforms to the delegate specified above.
Use the CSharpCodeProvider class to compile an assembly
with your custom function that returns the bool you want.
Run the dynamically written and compiled code from your main program.
Well as you may guess it is not going to be straight forward but at the same time it is not as hard a problem as it seems
You can perform a few steps to get what you want:
Get the search expression as input (for e.g. "PwC OR (Canadian AND thrive)")
Write an extension method on XElement that returns true and takes the search criteria as input. You will then be able to use
var selectedBook = from r in
document.Root.Descendants("Archives").Elements("Headline").Elements("Para")
where r.SatisfiesCriteria(searchCriteria)
select r;
Write a parser class that parses searchCritera and stores it in parsed format. (for e.g. you can convert it into postfix notation). This is quite easy and you can use standard algorithm for this. For your purpose OR, AND will be operators and PwC etc. will be operands. Parenthesis will get removed as part of parsing.
Now simply invoke this parser from with in your extension method and then evaluate the postfix expression you get. This again can be done through standard stack based evaluation. Infact it would be better if you parse the criteria once and then only evaluate in where. While evaluating you need to replace the operands with r.Value.Contains
It seems like a good scenario for http://scriptcs.net/

Why does it compile?

var cv = (new CustomValidator()
{
ErrorMessage="Formato de telefone inválido",
ControlToValidate = "txtTelefoneIni", //<-- see the extra comma
});
Because it is legal syntax.
Really, it is.
When you're constructing an object using the object initializer syntax, you're allowed to leave a trailing comma after the last item, even if you end the initializer block there and then.
The reason behind it is probably that it makes it easier to come back and edit it later, as forgetting to add a comma after the previously-last-item is the #1 compile-time-problem with object-initializers.
It's intentional. Also works on enum members. (so it's easier to add more stuff)
Why should it not compile?
This type of syntax is legal in Python as well.
It compiles because it is valid C# syntax. You can also do the same thing with arrays
string[] meh = { "a", "b", "c", };
It is part of the C# language specification: Object initializers.
Because it's allowed.
Generally, allowing trailing comma in such forms (and actually using that "privilege") is useful so that programmers can add more items to the list without the risk of having forgotten to add comma at the end of the previous item.
Its a valid syntax in C#
lets see
var c = new List<int>() { 1, 2, 3 ,};
FWIW, it was already valid in C.
My favorite reason to use such a syntax (especially when defining enums) is that when you add an item to the list, the source control sees changes in one line only (the new one). It doesn't tag the previusly one as modified (because of added comma). Much more readable diff.
My 2-cents.

Categories