Cannot assign new value to LINQ-selected data - c#

namespace ConsoleApplication4
{
class T1
{
public int MyProperty { get; set; }
}
class Program
{
static void Main(string[] args)
{
var tmp = (new[] { 1, 3, 4 }).Select(x =>new T1 { MyProperty=x});
foreach (var s in tmp)
{
s.MyProperty = 9;
}
foreach (var s in tmp)
{
Console.WriteLine(s.MyProperty);
}
Console.ReadLine();
}
}
}
I expect there are three 9 on screen, but the values are still same.
However, if I modify code a little bit, the values would be changed successfully i.e. :
var tmp = (new[] { 1, 3, 4 }).Select(x =>new T1 { MyProperty=x}).ToList();
I wonder why?

The reason is deferred execution.
tmp is not a list or an array. It's only a definition how to create the enumeration. Or in other words: tmp is only the question, but not the answer.
So in the second foreach, the enumerator created by the Select is executed again, creating new instances of T1.
When you use .ToList() instead, the enumeration is converted to a List (so tmp is a List<T1>). And you can iterate that List as often as you want without creating new instances.

Related

Why every list is modificated in this sample? [duplicate]

This question already has answers here:
Both c# lists being modified
(6 answers)
Closed 1 year ago.
I wanted to initialize my class with the list of ints for example:
{1,5,6,7,1,0} and then modify them and get two fields, one with the same list of ints and the second with a modified list of ints. But as a result, I get two modified lists with values: {0,4,5,6,0,0}. Can someone explain to me why this code acts like this?
MyClass
public class MyClass
{
public List<int> numbers { get; }
public List<int> diffrentNum { get; set; }
public MyClass(List<int> _numbers)
{
numbers = _numbers;
diffrentNum = GetNumbers();
}
private List<int> GetNumbers()
{
List<int> localNumbers = numbers;
for (int i=0;i<localNumbers.Count-1;i++)
{
if (localNumbers[i] > 0)
{
localNumbers[i]--;
}
}
return localNumbers;
}
}
Main
static void Main(string[] args)
{
List<int> someDate = new List<int>();
someDate.Add(1);
someDate.Add(5);
someDate.Add(6);
someDate.Add(7);
someDate.Add(1);
someDate.Add(0);
MyClass myclass= new MyClass(someDate);
Console.WriteLine(String.Join("", new List<int>(someDate).ConvertAll(i => i.ToString()).ToArray()));
Console.WriteLine(String.Join("", new List<int>(myclass.numbers).ConvertAll(i => i.ToString()).ToArray()));
Console.WriteLine(String.Join("", new List<int>(myclass.diffrentNum).ConvertAll(i => i.ToString()).ToArray()));
Console.ReadKey();
}
By calling List<int> localNumbers = numbers; you're assigning both variables to point to the same object, so any changes made through one of them are visible through the other.
One way to create a copy of a list is by using Linq's ToList:
List<int> localNumbers = numbers.ToList();

How to set flag in one list for the Id's which match with the Id's in another list using Lambda expression c#

I have two lists classes
public class class1{
public Int Id { get; set; }
public Bool Flag{ get; set; }
}
public class class2{
public Int Id { get; set; }
}
Now i have List<class1> and List<class2>,
Now i have to update Flag property to true in List<class1> for only those Ids which match with the Id's present in List<class2> using lambda expression c#.Don't want to use foreach.
using lambda expression. Don't want to use foreach.
That's usually a silly requirement and a hallmark that you're not really familiar with C#, Linq or performance analysis. You have a collection whose elements you want to modify, so you should use foreach().
If you're trying out functional programming, then you should treat the list elements as immutable and project into a new collection.
The first part of your problem, looking up which list elements to modify based on a presence of one of their properties in another collection's elements' properties, is trivial:
var elementsToModify = list1.Where(l1 => list2.Any(l2 => l2.Id == l1.Id));
Now with a foreach(), this'll be simple:
foreach (var l1 in elementsToModify)
{
l1.Flag = true;
}
Or, even denser (not that less code equals more performance):
foreach (var l1 in list1.Where(l1 => list2.Any(l2 => l2.Id == l1.Id)))
{
l1.Flag = true;
}
So, there's your code. But you didn't want to use foreach(). Then you need to project into a new collection:
var newList1 = list1.Where(l1 => list2.Any(l2 => l2.Id == l1.Id))
.Select(l1 => new Class1
{
Id = l1.Id,
Flag = true,
})
.ToList();
There you have it, a List<Class1> with only flagged items. Optionally you could use this list in a foreach() to update the original list1. Oh, wait.
The below solution does not use the classical "for each", but is compiled to one under the hood. If that's not what you meant, then please explain what you are trying to achieve. Using for each in this example is a good approach. One could also use while or for loops, but is it really what's being asked here?
Object definition:
public class MyObject
{
public int Id { get; set; }
public bool Flag { get; set; }
}
List initialization:
var list = new List<MyObject>()
{
new MyObject() { Id= 1 },
new MyObject() { Id= 2 },
new MyObject() { Id= 3 },
new MyObject() { Id= 4 }
};
var list2 = new List<MyObject>()
{
new MyObject() { Id= 2 },
new MyObject() { Id= 4 }
};
Code:
list.ForEach(el => el.Flag = list2.Any(el2 => el2.Id == el.Id));
EDIT:
An example with a while loop (a bit nasty to do it this way):
int i = -1;
int numberOfElements = list.Count;
while (++i < numberOfElements)
{
list[i].Flag = list2.Any(el => el.Id == list[i].Id);
}
I guess you can write a for loop yourself...

Convert object to IEnumerable of anonymous type

How do I iterate over the anonymous type that is passed in as an object below (first, second, third) => new { One = first, Two = second, Three = third }
If I interrogate the type of message and print it, it says:<>f__AnonymousType0 3[MtApi.MtQuote,MtApi.MtQuote,MtApi.MtQuote]
//**How do I convert an object to the anonymous type?**
static void ShowAnonymousTypeMessage(object message)
{
foreach(var quote in message)
Console.WriteLine(
quote.Instrument + ": " + quote.Bid.ToString() + quote.Ask.ToString());
}
...
var pattern = observable1.And(observable2).And(observable3);
var plan = pattern.Then((first, second, third) => new { One = first, Two = second, Three = third });
var zippedSequence = Observable.When(plan);
zippedSequence.Subscribe(
ShowAnonymousTypeMessage
);
This is working for me:
static void Main()
{
var anon = new { Name = "Terry", Age = 34 };
test(anon);
}
static void test(dynamic t)
{
Console.WriteLine(t.Age);
Console.WriteLine(t.Name);
}
Anonymous types aren't intended to be passed around and you should only use object when absolutely necessary. Also you can't iterate over an anonymous type - you should use an Array.
var pattern = observable1.And(observable2).And(observable3);
var plan = pattern.Then((first, second, third) => new[] { first, second, third });
var zippedSequence = Observable.When(plan);
zippedSequence.Subscribe(
ShowAnonymousTypeMessage
);
Anonymous types aren't meant to be passed around, for the same reason we have strong typing in C# at all: The compiler doesn't make careless errors or forget things, and we often do. If your anonymous class instances are leaving the scope where they were created, it's time for them to grow up and be a real class.
Usually I'd say you should write a quickie class with appropriate properties (guessing at the property types here):
public class Thing {
public String One { get; set; }
public String Two { get; set; }
public String Three { get; set; }
}
But a Tuple<T1,T2,T3> is just as good really, if you've got property names like One, Two, and Three anyway:
public static void Main()
{
var x = Enumerable.Range(0, 10).Select(n => new Tuple<int, string>(n, $"Item {n + 1}"));
Test(x);
}
private static void Test(IEnumerable<Tuple<int, string>> stuff)
{
foreach (var item in stuff)
{
Console.Write($"{item.Item1}: {item.Item2}");
}
}
dynamic works, but dynamic is like the Vise-Grip: "Always the Wrong Tool for Every Job, Since 1921". dynamic has a legitimate but small role in the typesystem. It's not there so we can turn the whole language into JavaScript.
public static Main()
{
var x = Enumerable.Range(0, 10).Select(n => new { ID = n, Value = $"Item {n + 1}" });
Test(x);
}
private static void Test(dynamic message)
{
foreach (dynamic item in message)
{
Console.Write($"{item.ID}: {item.Value}");
}
}
OK, the Vise-Grip isn't always the wrong tool either. But it's rare there isn't a better one.

Am I using the LINQ .OfType() operator correctly?

public class Stock
{
}
class Program
{
static void Main(string[] args)
{
ObjectCache cache = MemoryCache.Default;
cache["test"] = new Stock();
var x = cache.OfType<Stock>().ToList();
}
}
This is returning empty ...I thought OfType is supposed to return all instances in a collection of type T ?
Just to rule out the ObjectCache as a possible culprit I also tried
List<object> lstTest = new List<object>();
lstTest.Add(new Stock());
var y = lstTest.OfType<Stock>().ToList();
This works however - so it seems like the problem is with the ObjectCache, which is an instance of a Dictionary underneath
SOLUTION
cache.Select(item => item.Value).OfType<T>().ToList()
Thanks Alexei!
MemoryChache returns enumerator of KeyValuePair<string,Object>, not just values: MemoryChache.GetEnumerator().
You need to case accordingly to get your items. Something like:
var y = cache.Select(item => item.Value).OfType<Stock>();
This would work
cache.GetValues(new string[] {"test"}).Values.OfType<Order>()
But I don't think you should use this.
Cache works like a Dictionary...so you can get set of KeyValuePairs with GetValues
This worked for me.
public class Stock
{
public Stock()
{
Name = "Erin";
}
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
System.Collections.ArrayList fruits = new System.Collections.ArrayList(4);
fruits.Add("Mango");
fruits.Add("Orange");
fruits.Add("Apple");
fruits.Add(3.0);
fruits.Add("Banana");
fruits.Add(new Stock());
// Apply OfType() to the ArrayList.
var query1 = fruits.OfType<Stock>();
Console.WriteLine("Elements of type 'stock' are:");
foreach (var fruit in query1)
{
Console.WriteLine(fruit);
}
}
}
Remember IEnumerable is lazily evaluated. Use a foreach to loop through query1 and you will see it only find the Stock object.
Yeah. Sorry myself. ObjectCache is a IEnumerable>
Not really an IDictionary.
This works:
var c = cache.Select(o => o.Value).OfType<Stock>().ToList();

Best way to implement "ReOrderable Collection" and Persist it to database

My domain object :
public class MyDomainObject
{
public Guid Id { get; set; }
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
Assuming sample data :
var list = new List<MyDomainObject>()
{
new MyDomainObject {Name = "Element1", DisplayOrder = 0},
new MyDomainObject {Name = "Element2", DisplayOrder = 1},
new MyDomainObject {Name = "Element3", DisplayOrder = 2},
new MyDomainObject {Name = "Element4", DisplayOrder = 3},
};
Now i change the DisplayOrder of the "Element3" from 2 to 1. My list should looks like that :
Element1 (DisplayOrder = 0)
Element3 (DisplayOrder = 1)
Element2 (DisplayOrder = 2)
Element4 (DisplayOrder = 3)
Now i remove "Element3"
Element1 (DisplayOrder = 0)
Element2 (DisplayOrder = 1)
Element4 (DisplayOrder = 2)
So what's the best way to persist this mechanism to database ?
Basically i need a "ReOrderableCollection" which will be populated from database with an OrderBy "DisplayOrder" where Collection Index Match "DisplayOrder", and persist back items by assigning DisplayOrder from Collection Index.
I answered a previous/similar question about re-ordering here:
How to design table that can be re-sequenced?
This does a good job of resaving the Order with no gaps. Depending on the size the lists resaving the Order may be a perfectly viable option, for long lists Mark Byers' idea looks pretty good.
From your examples it seems that you always want the sequence to be without gaps, starting from zero. But this means that removing the first element will require updating the row in the database for every single item in your list. It's simple and it will work (and these are good things) but it's not always ideal. Since you asked for "the best way" without really specifying what you mean by that, allow me to suggest an alternative method:
What really matters with a DisplayOrder is not the actual values but their relative order. If you want to improve performance with the database, you could consider relaxing the requirement that there should be no gaps and then try to find the smallest number of changes to the DisplayOrders to ensure that the correct order is stored, even if gaps are present in the resulting sequence. If you do this then adding, removing or moving a single item will typically only require updating one row in the database, with the exception that occasionally other items will have to be moved to create a gap where an item must be inserted between two others that have consecutive DisplayOrders.
You can also minimize the number of times that a gap is not available by starting with DisplayOrder 100, 200, 300 and later allowing for example an insertion with DisplayOrder 150 in between (or perhaps use a real/float type instead of an integer).
Another advantage of this method is if you use a database data comparison tool to observe changes between the current version of the database and older versions it will be easier to see what modifications have been made to the display order. You will only see changes in the display order of items that have actually been moved by the user, rather than half the list change each time an item is removed. It will also reduce the size of backups if you use an incremental backup strategy.
I'd say though that these advantages are not significant advantages over the naive method for most cases. It depends on your system whether it is worth implementing this system or just keeping it simple. If in doubt, keep it simple. For systems with small lists, few modifications and where you don't care about the change history, overwriting the entire list with new DisplayOrders each time will probably be just fine.
For what I can see it seems that DisplayOrder has the same value of the index property of the collection. So I will try to use that instead of a DisplayOrder property. On the DB I will use the DisplayOrder column to read and save the items but not on the domain objects.
HTH
ema
Now I'm assuming that you do want to always reorganize your list so that the DisplayOrder starts at 0 and increases without gaps, and you want this to happen automatically. You could implement your own collection type and an interface IDisplayOrderable and have the members of your type that change the list also automaticaly update the DisplayOrder of the items in the collection. As opposed to my other answer which was about an alternative way to store the data in the datase, this answer shows how to write a client class that could make it easier to automatically synchronize the DisplayOrder in your objects with your list indexes so that when you are ready to submit the changes to the database, the DisplayOrder field is already set correctly for you.
I think the answer is best given as some source code:
using System;
using System.Collections.Generic;
using System.Linq;
interface IDisplayOrderable
{
int DisplayOrder { get; set; }
}
class ReorderableList<T> : IList<T> where T : IDisplayOrderable
{
List<T> list = new List<T>();
private void updateDisplayOrders()
{
int displayOrder = 0;
foreach (T t in list)
{
t.DisplayOrder = displayOrder++;
}
}
public ReorderableList() { }
public ReorderableList(IEnumerable<T> items)
{
list = new List<T>(items.OrderBy(item => item.DisplayOrder));
}
public void Insert(int index, T item)
{
list.Insert(index, item);
updateDisplayOrders();
}
public void Add(T item)
{
list.Add(item);
updateDisplayOrders();
}
public bool Remove(T item)
{
bool result = list.Remove(item);
if (result)
updateDisplayOrders();
return result;
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
// TODO: Other members and methods required to implement IList<T>...
}
class Item : IDisplayOrderable
{
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
class Program
{
static void Main()
{
Item foo = new Item { Name = "foo", DisplayOrder = 0 };
Item bar = new Item { Name = "bar", DisplayOrder = 1 };
Item baz = new Item { Name = "baz", DisplayOrder = 2 };
// Pretend this came from the database.
IEnumerable<Item> query = new Item[] { bar, foo };
// The constructor automatically reorder the elements.
ReorderableList<Item> items = new ReorderableList<Item>(query);
items.Add(baz);
items.Remove(foo);
items.Insert(1, foo);
foreach (Item item in items)
Console.WriteLine("{0} : {1}", item.Name, item.DisplayOrder);
}
}
Output:
bar : 0
foo : 1
baz : 2
Perhaps this was the sort of answer you were looking for?
I maybe founded a solution by creating a custom List which take an Lamba Expression in constructor parameter in order the list to be able to self update items property "DisplayOrder".
The sample class
public class MyItem
{
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
The sample program
public class Program
{
static void Main(string[] args)
{
var list = new DisplayOrderableList<MyItem>(p => p.DisplayOrder)
{
new MyItem{ Name = "Item 1"},
new MyItem{ Name = "Item 2"},
new MyItem{ Name = "Item 3"},
};
var item = list.Where(p => p.Name == "Item 2").FirstOrDefault();
list.MoveUp(item);
list.ForEach(p => Console.WriteLine("{0}-{1}", p.Name, p.DisplayOrder));
Console.WriteLine();
list.MoveDown(item);
list.ForEach(p => Console.WriteLine("{0}-{1}", p.Name, p.DisplayOrder));
Console.WriteLine();
Console.ReadLine();
}
}
The custom implementation of DisplayOrderableList
public class DisplayOrderableList<T> : List<T>
{
#region Private Fields
private PropertyInfo _property;
#endregion
#region Constructors
public DisplayOrderableList(Expression<Func<T, int>> expression)
{
ValidateExpression(expression);
}
#endregion
#region Public Methods
public void MoveUp(T item)
{
if (!Contains(item))
throw new ArgumentNullException("item", "item doesn't exists in collection");
var idx = IndexOf(item);
RemoveAt(idx);
if (idx > 0)
Insert(idx - 1, item);
else
Insert(0, item);
UpdateDisplayOrder();
}
public void MoveDown(T item)
{
if (!Contains(item))
throw new ArgumentNullException("item", "item doesn't exists in collection");
var idx = IndexOf(item);
RemoveAt(idx);
if (idx + 1 > Count)
Add(item);
else
Insert(idx + 1, item);
UpdateDisplayOrder();
}
#endregion
#region Private Methods
private void UpdateDisplayOrder()
{
foreach (var item in this)
{
_property.SetValue(item, IndexOf(item), null);
}
}
#endregion
#region Expression Methods
private void ValidateExpression(Expression<Func<T, int>> expression)
{
var lamba = ToLambaExpression(expression);
var propInfo = ToPropertyInfo(lamba);
if (!propInfo.CanWrite)
{
throw new ArgumentException(String.Format("Property {0} as no setters", propInfo.Name));
}
_property = propInfo;
}
private static LambdaExpression ToLambaExpression(Expression expression)
{
var lambda = expression as LambdaExpression;
if (lambda == null)
{
throw new ArgumentException("Invalid Expression");
}
var convert = lambda.Body as UnaryExpression;
if (convert != null && convert.NodeType == ExpressionType.Convert)
{
lambda = Expression.Lambda(convert.Operand, lambda.Parameters.ToArray());
}
return lambda;
}
private static PropertyInfo ToPropertyInfo(LambdaExpression expression)
{
if (expression == null)
{
throw new ArgumentNullException("expression", "Expression cannot be null.");
}
var prop = expression.Body as MemberExpression;
if (prop == null)
{
throw new ArgumentException("Invalid expression");
}
var propInfo = prop.Member as PropertyInfo;
if (propInfo == null)
{
throw new ArgumentException("Invalid property");
}
return propInfo;
}
#endregion
}
This now get the following output :
Item 2-0
Item 1-1
Item 3-2
Item 1-0
Item 2-1
Item 3-2
It's a proof of concept and should be enhanced but it's a beggining.
What do you think about this ?
I know this is a old question, but the comments here and in another question helped me solve a similar issue and I wanted to provide my code in case it helps anyone else out looking for something similar. You can find my code at the following link:
How to design table that can be re-sequenced?

Categories