My intention is to... void Encrypt any property value in 'TSource', it could be all or some of properties depend on selector.
This is my former code:
...IEnumerable<TSource>().ForEach(delegate(TSource ts)
{
ts.prop0 = ts.prop0.Encrypt();
ts.prop1 = ts.prop1.Encrypt();
Etc...
});
IEnumerable Extension :
...ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
{
foreach (TSource item in source)
action(item);
}
string Extension :
...string Encrypt(this string strPlainText)
{
if (!string.IsNullOrEmpty(strPlainText))
return SomeClass.Encrypt(strPlainText);
return strPlainText;
}
The point is how to transform all above into IEnumerable Extension just in line syntax,may or may not look like this:
//Encrypt all props. in Tsource.
...IEnumerable<TSource>().EncryptProp();
//Encrypt any prop. in Tsource. with selector property
...IEnumerable<TSource>().EncryptProp(ts => ts.prop0);
...IEnumerable<TSource>().EncryptProp(ts => ts.prop0,ts.prop1);
...IEnumerable<TSource>().EncryptProp(ts => ts.prop0,ts.prop1,Etc...);
I'd be glad to take any suggestions.
It is hard to tell exactly how this could be done because you code sample is incomplete. However, from what I can understand, you have an IEnumerable<TSource> and you would like to perform the same operation for all of the properties for all of the items in this sequence?
This requires a couple of things, first look at SelectMany. This projects each element in the source to a new sequence, flattening them all into a single sequence.
The second thing is how to create an IEnumerable<TResult> from all of the properties of each element. This is not so easy! If your Prop0, Prop1 could be stored as a dictionary that would help!
You could use reflection. Something like this:
IEnumerable<MyObject> source = ///your source
var allProperties = source.SelectMany(s =>
typeof(MyType).GetProperties().Select(p => p.GetValue(s, null));
However, as strings are immutable, if you Encrypt the resulting sequence, your source MyObject instances will not reflect this change.
If you really want to do this, store your properties in a dictionary!
Related
I have a List<Person> and instead want to convert them for simple processing to a List<string>, doing the following:
List<Person> persons = GetPersonsBySeatOrder();
List<string> seatNames = persons.Select(x => x.Name).ToList();
Console.WriteLine("First in line: {0}", seatNames[0]);
Is the .Select() statement on a LINQ to Objects object guaranteed to not change the order of the list members? Assuming no explicit distinct/grouping/ordering is added
Also, if an arbitrary .Where() clause is used first, is it still guaranteed to keep the relative order, or does it sometimes use non-iterative filtering?
As Fermin commented above, this is essentially a duplicate question. I failed on selecting the correct keywords to search stackoverflow
Preserving order with LINQ
It depends on the underlying collection type more than anything. You could get inconsistent ordering from a HashSet, but a List is safe. Even if the ordering you want is provided implicitly, it's better to define an explicit ordering if you need it though. It looks like you're doing that judging by the method names.
In current .Net implementation it use such code. But there are no guarantee that this implementation will be in future.
private static IEnumerable<TResult> SelectIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
int index = -1;
foreach (TSource source1 in source)
{
checked { ++index; }
yield return selector(source1, index);
}
}
Yes, Linq Select is guaranteed to return all its results in the order of the enumeration it is passed. Like most Linq functions, it is fully specified what it does. Barring handling of errors, this might as well be the code for Select:
IEnumerable<Y> Select<X, Y>(this IEnumerable<X> input, Func<X, Y> transform)
{
foreach (var x in input)
yield return transform(x);
}
But as Samantha Branham pointed out, the underlying collection might not have an intrinsic order. I've seen hashtables that rearrange themselves on read.
I am reading C# AsEnumerable:
"The IEnumerable interface is a generic interface. This means it
defines a template that types can implement for looping. The
AsEnumerable method, a generic method, allows you to cast a specific
type to its IEnumerable equivalent"
Further on, a code example:
using System;
using System.Linq;
class Program
{
static void Main()
{
// Create an array type.
int[] array = new int[2];
array[0] = 5;
array[1] = 6;
// Call AsEnumerable method.
var query = array.AsEnumerable();
foreach (var element in query)
{
Console.WriteLine(element);
}
}
}
Sounds like I need to convert an array to an IEnumerable type object to use looping (foreach?).
But applying foreach directly to an array yields exactly the same results:
using System;
//using System.Linq;
class Program
{
static void Main()
{
// Create an array type.
int[] array = new int[2];
array[0] = 5;
array[1] = 6;
// Call AsEnumerable method.
//var query = array.AsEnumerable();
foreach (var element in array)
{
Console.WriteLine(element);
}
}
}
So, the entire webpage with an explanation of AsEnumerable() method is void for me.
What did I miss?
The example is bad and it should feel bad. Here is a better, if somewhat contrived example:
If I have an extension method defined on the, let's say, the array type, like this:
public static class ArrayExtension {
public static bool Any<T>(this T[] source, Func<T,bool> predicate)
{
Console.WriteLine("Undesirable side behaviour");
SomeResourceIntensiveOperation();
Console.WriteLine("Inefficient implementation");
return source.Where(predicate).Count() != 0;
}
}
and I do
int[] nums = new []{1,2,3,4,5};
nums.Any(n=> n % 2 == 0);
If will execute and run my implementation, even if i do not need that. By doing
nums.AsEnumerable().Any(n => n % 2 == 0);
it will call the default implementation.
The real benefit is when you are using IQueryable implementations (e.g. LINQ-to-SQL), because, for example, the Where for IEnumerable is defined as
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
but the IQueryable.Where is defined with
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate)
When the IQueryable behaviour is undesireable one can call the AsEnumerable() to force the IEnumerable behaviour.
From MSDN
The AsEnumerable<TSource>(IEnumerable<TSource>) method has no effect other than to change the compile-time type of source from a type that implements IEnumerable<T> to IEnumerable<T> itself.
AsEnumerable<TSource>(IEnumerable<TSource>) can be used to choose between query implementations when a sequence implements IEnumerable<T> but also has a different set of public query methods available. For example, given a generic class Table that implements IEnumerable<T> and has its own methods such as Where, Select, and SelectMany, a call to Where would invoke the public Where method of Table. A Table type that represents a database table could have a Where method that takes the predicate argument as an expression tree and converts the tree to SQL for remote execution. If remote execution is not desired, for example because the predicate invokes a local method, the AsEnumerable<TSource> method can be used to hide the custom methods and instead make the standard query operators available.
It makes no sense in YOUR example logically (i.e. from array). I would assume the first code has been written by a beginner, or - more down - an example.
It does make sense in the sense of LINQ as "AsEnumerable" triggers the evaluation of the query and depending on the ORM That can mean freeing up a database connection for a reuse within the loop.
THAT SAID:
You read too much into examples. In an example, code is there not to be "good" but to show a point. In this case it may make sense to DEMONSTRATE the use of AsEnumerable - and an Array is the fastest enumerable object to initialize (in terms of lines of code), to keep the example short. Examples point out specific things, they are not "good code" for anything.
This is just another example. Suppose I have this method:
static void MyMeth(int[] numbers)
{
var query = numbers.Reverse(); // works fine, calls Linq extension
// ... use query ...
}
Then I decide to change numbers into a List<int> instead, and try:
static void MyMeth(List<int> numbers)
{
var query = numbers.Reverse(); // will not compile!
// ... use query ...
}
The problem here is that the List<> class has another method which is also called Reverse. That method returns void (because it modifies the original List<> in-place). I don't want that. One solution would be to upcast numbers explicitly:
static void MyMeth(List<int> numbers)
{
var query = ((IEnumerable<int>)numbers).Reverse(); // fine; Linq
// ... use query ...
}
But another solution would be AsEnumerable<>, so:
static void MyMeth(List<int> numbers)
{
var query = numbers.AsEnumerable().Reverse(); // fine too; Linq
// ... use query ...
}
Conclusion: The purpose of AsEnumerable method is to "forget" methods on the specialized type that happen to "hide" the extension methods on the general type IEnumerable<>. This can be incredibly important in the case where the "specialized" type is/inherits IQueryable<> where there are (extension) methods Where, Select and so on which do something different (namely ingest the lambda as an expression tree, analyze it, and "translate" it into SQL or something) than do Where, Select etc. on IEnumerable<>.
I would like to add new iEnumerable object to original one. Can I do this updating original object in extenstion method like following?
public static void AddItems<TSource>(this IEnumerable<TSource> orginalColl,
IEnumerable<TSource> collectionToAdd)
{
foreach (var item in collectionToAdd)
{
orginalColl.ToList<TSource>().Add(item);
}
}
I am calling like this: OrgCollecation.AddItems(newCollection).
But this does not seems to work. Any idea?
An IEnumerable[<T>] is not intended for adding. You can concatenate (generating a new sequence), but that doesn't change the original sequence (/list/array/etc). You can do that with Enumerable.Concat, i.e. return orginalColl.Concat(...). But emphasis: this does not update the original collection.
What you could do would be to cast to IList[<T>] or similar, but that would be abusive (and will only work for some scenarios, not all). It won't work, for example, for anything that is based on an iterator block (or any other IEnumerable<T> that is not also an IList<T>) - for example it won't work on someSource.Where(predicte).
If you expect to change the source, then you should be passing in something like IList[<T>]. For example:
public static void AddItems<TSource>(this IList<TSource> orginalColl,
IEnumerable<TSource> collectionToAdd)
{
foreach (var item in collectionToAdd)
{
orginalColl.Add(item);
}
}
(btw, AddRange would be an alternative name for the above, to match List<T>.AddRange)
No you can not.
In your code you are cloning the source enumerable into list, then adding elements to it and forgetting, because you are not returning anything.
Try
var result = orginalColl.Concat(collectionToAdd);
Take a look at http://msdn.microsoft.com/en-us/library/bb302894.aspx for more information and examples.
In short, an IEnumerable<T> should be considered immutable, and you can't add to it. You don't know what kind of collection is implementing it, it may for example be a serial port input or a read only file in the file system you're enumerating from.
What you're trying to do to the collection matches the use case of ICollection<T> better; it's implemented by generic (mutable) collections in the framework.
public static void AddItems<TSource>(this ICollection<TSource> orginalColl,
IEnumerable<TSource> collectionToAdd)
{
foreach (var item in collectionToAdd)
{
orginalColl.Add(item);
}
}
Sorry if the title is misleading, wasn't sure how to describe this one.
My end goal is to have an extension method of IQueryable<T> and some form (see below for example) of expression that will allow me to have to return an IQueryable<EntityIndex<T>> (or similar) which contains the original T in the Entity field, and an array/ienumerable containing the elements as describe by the some form of expression.
I know that doesn't really make sense, hopefully it will after an example...
This is what I have so far:
class EntityIndex<T, TKey>
{
T Entity { get; set; }
// Doesn't have to be IEnumerable, whatever is easier
IEnuermable<TKey> Index { get; set; }
}
static class Elsewhere
{
[Extension()]
public IQueryable<EntityIndex<T, TKey>> IndexBy<T, TKey>(this IQueryable<T> source, Expression<Func<T, TKey[]>> indexSelector)
{
return source.Select(n => new EntityIndex<T, TKey> {
Entity = n,
Index = new T[] { n }.Select(indexSelector)
});
}
}
Note: The above does not compile, it's simply there to try and show what I'm trying to achieve.
I've used the standard selector, but sub-optimally, had to arbitrarily create an array of T on the assignment to the 'Index' property to be able to apply the selector. I'm hoping a better choice of parameter may resolve this, but possibly not. The main issue is this doesn't compile so if there is a minor tweak that will allow it to work that's fine by me, if you can understand my gibberish and understand what I'm trying to do, and happen to know a better way to go about it I'd be greatly appreciative.
Ideally, I need the solution to be understood by the L2S engine, which I'm not convinced the above is thanks to the introduction of the EntityIndex class, but I'm holding out hope that it'll treat it as an anonymous class.
EDIT:
Good point Damien, the bigger picture is probably much easier to describe...
I want an extension method that accepts an expression, the expression should describe which fields on the entity to index, which will be used after this particular expression to allow a criterion (where clause) to be applied to the selected fields.
Long story short, in a number of places in code we have a wildcard string search. If I have an EntityA with Property1, Property2, Property3, etc, it is not uncommon to see code such as:
Handwritten, please excuse minor typos
public string[] WildcardSearch(string prefixText, int count)
{
string searchTerm = prefixText.Replace(wildcard, string.Empty);
if (prefixText.StartsWith(wildcard) && prefixText.EndsWith(wildcard)) {
return entitySet.Where(n => n.Property1.Contains(searchTerm) || n.Property2.Contains(searchTerm)).Select(n => n.Property3).ToArray();
} else if (prefixText.StartsWith(wildcard)) {
return entitySet.Where(n => n.Property1.EndsWith(searchTerm) || n.Property2.EndsWith(searchTerm)).Select(n => n.Property3).ToArray();
// you get the picture, same with EndsWith, no wildcards defaults to contains...
}
}
EDIT:
Further clarification - using the above WildcardEarch as an example, what I was hoping for was to be able to have a selector as follows or similar:
Func<EntityA, IEnumerable<string>> indexSelector = n => new string[] {
n.Property1,
n.Property2
};
// Alternatively, a ParamArray of keySelector might work?
Func<EntityA, string>[] keySelectors = new Func<EntityA, string>[] {
n => n.Property1,
n => n.Property2
};
Given an adequate expression describing which fields on the entity to search, returning the IQueryable<EntitySearch<T>> as shown above, I hoped to be able to apply a single criterion, similar to:
Func<EntitySearch<T>, bool> criterion = n => false;
if (wildcardIsContains) {
criterion = n => n.Values.Any(x => x.Contains(searchTerm));
} else if (wildCardIsStartsWith) {
criterion = n => n.Values.Any(x => x.Contains(searchTerm));
//etc
}
Given the extension at the very top that I can't get to work, and this criterion logic, I should be able to take an IQueryable<T>, select some fields, and apply an appropriate wildcard search on the fields, finally returning IQueryable<T> again having added the filtering.
ThanksĀ¬!
Please comment if you need more information/clarification...
EDIT:
Fair one #subkamren and thanks for the interest. Some non-generic examples may be of use. I'll draft something up and add them shortly. For the time being, some clarification based on your comment...
Given an IQueryable<Animal> I want an extension allowing me to select fields on Animal which I intend to search/index by. For example, Animal.Description, Animal.Species.Name etc. This extension should return something like an IIndexedQueryable<Animal>. That is the issue I'm trying to deal with in the question above. The wider picture mentioned, which I'd be exceptionally pleased if you're willing to help with, is as follows:
The IIndexedQueryable<T> interface in turn I would like an extension for which could take a string search term. The extension should resolve the wildcards within the search term, extend the original IQueryable with the necessary criterion to perform a search on the indexed fields, and return an IQueryable<T> again.
I appreciate this could be done in a single step, but I hoped to do it this way so that later on I can look into adding a third extension method applicable to IIndexedQueryable<T> allowing me to perform a freetext search with SQL Server... ^^ Make any sense?
That's the bigger picture at least, this question deals primarily with being able to specify the fields I aim to index in such a way I can use them thereafter as mentioned here.
So something like:
public static IEnumerable<EntityIndex<T, Y>> IndexBy<T, Y>(this IEnumerable<T> entities, Func<T, Y> indexSelector) {
return entities.Select(e => new EntityIndex<T, Y> { Entity = e, IndexValue = indexSelector(e) });
}
Noting that generically defining EntityIndex with the TIndexType (called Y here) is important because you don't know ahead of time what the index is. The use of a generic allows Y to be an enumeration, thus the following would work as an index selector:
// Assuming Animal has attributes "Kingdom", "Phylum", "Family", "Genus", "Species"
// this returns an enumeration of EntityIndex<Animal, String[]>
var animalsClassified = someAnimals.IndexBy(a => new String[] { a.Kingdom, a.Phylum, a.Family, a.Genus, a.Species });
EDIT (Adding further detail):
Using the above, you can group the results by unique index value:
var animalClassifications = animalsClassified
.SelectMany(ac => ac.IndexValue.Select(iv => new { IndexValue = iv, Entity = ac.Entity }))
.GroupBy(kvp => kvp.IndexValue)
What I've described here, by the way, is (a very simplified form of) the MapReduce algorithm as popularized by Google. A distributed form of the same is commonly used for keyword identification in text search, where you want to build an index of (search term)->(list of containing documents).
If I have two sequences and I want to process them both together, I can union them and away we go.
Now lets say I have a single item I want to process between the two sequencs. I can get it in by creating an array with a single item, but is there a neater way? i.e.
var top = new string[] { "Crusty bread", "Mayonnaise" };
string filling = "BTL";
var bottom = new string[] { "Mayonnaise", "Crusty bread" };
// Will not compile, filling is a string, therefore is not Enumerable
//var sandwich = top.Union(filling).Union(bottom);
// Compiles and works, but feels grungy (looks like it might be smelly)
var sandwich = top.Union(new string[]{filling}).Union(bottom);
foreach (var item in sandwich)
Process(item);
Is there an approved way of doing this, or is this the approved way?
Thanks
One option is to overload it yourself:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, T item)
{
return source.Union(Enumerable.Repeat(item, 1));
}
That's what we did with Concat in MoreLINQ.
The new way of doing this, supported in .NET Core and .NET Framework from version 4.7.1, is using the Append extension method.
This will make your code as easy and elegant as
var sandwich = top.Append(filling).Union(bottom);
Consider using even more flexible approach:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, params T[] items)
{
return source.Union((IEnumerable<T>)items);
}
Works for single as well as multiple items.
You may also accept null source values:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, params T[] items)
{
return source != null ? source.Union((IEnumerable<T>)items) : items;
}
I tend to have the following somewhere in my code:
public static IEnumerable<T> EmitFromEnum<T>(this T item)
{
yield return item;
}
While it's not as neat to call col.Union(obj.EmitFromEnum()); as col.Union(obj) it does mean that this single extension method covers all other cases I might want such a single-item enumeration.
Update: With .NET Core you can now use .Append() or .Prepend() to add a single element to an enumerable. The implementation is optimised to avoid generating too many IEnumerator implementations behind the scenes.