Some methods in c# that i have seen , requires IEnumerable<IEnumerable<"some class">>. When method need IEnumerable<"some class"> as a parameter , i can pass a one-dimensional array or list . I thought by the same logic i can pass two-dimensional array as IEnumerable<IEnumerable<"some class">> , but my compiler says it is not the same. What data types i can pass to such methods, for example?
For example IEnumerable<IEnumerable<int>> is an enumeration of an enumeration of integers.
https://www.codingame.com/playgrounds/213/using-c-linq---a-practical-overview/ienumerablet
https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
It means that each element of the root list is a list of int.
If we write:
IEnumerable<IEnumerable<int>> listOfLists = GetItems();
We can parse items like that:
foreach ( var list in listOfLists )
{
Console.WriteLine("Values");
foreach ( var value in list )
Console.WriteLine(" " + value);
}
In fact if we declare:
var items = new List<List<int>>();
This is a IEnumerable<IEnumerable<int>> here.
It is like an array of arrays of int:
var items = int[][];
Here it is not a multidimentionnal array but a jagged array:
https://learn.microsoft.com/dotnet/csharp/programming-guide/arrays/jagged-arrays
https://www.tutorialsteacher.com/csharp/csharp-jagged-array
https://www.c-sharpcorner.com/UploadFile/puranindia/jagged-arrays-in-C-Sharp-net
IEnumerable is just an interface, which is implemented by a lot classes/types, two of which the List and Array (you can find the list here).
So, as as example, when the compiler tells you must pass a IEnumerable<"some class"> parameter it can be, for instance a List (depending if the "some class" refers to a string... if it refers to a class Car created by you then you must pass a List...) or string[] (which is an array of strings, which also implements this interface).
If you have to pass a IEnumerable<IEnumerable<"some class">> that means you have to have to layers of objects which implement the IEnumerable interface. You can have things like:
List<List>
string[][]
And others...
Long story short, it’s an interface that allows you to do a foreach loop on certain objects.
Related
I'm trying to select a random user control within an array list. I get the index of the array but it tells me it cannot simply convert int to UserControl. Anyone knows what I did wrong?
ArrayList notiList = new ArrayList();
int count = 0;
int i;
public MainPage()
{
this.InitializeComponent();
foreach (NotiObject noti in itemsPanel.Children.Where(c => c is NotiObject))
{
notiList.Add(noti);
System.Diagnostics.Debug.WriteLine(noti);
}
i = new Random().Next(0, notiList.Count);
}
void sendNotification()
{
NotiObject randomNoti = notiList.IndexOf(i);
}
As Dai has hinted, ArrayList is a particularly old thing, from back in the days when .net was relatively new and didn't have the incredibly useful feature known as generics.
The manual page for ArrayList says this (my emphasis):
Important
We don't recommend that you use the ArrayList class for new development.
Instead, we recommend that you use the generic List class.
Even the manufacturer is saying "don't use this product"
The big problem with ArrayList is that because it wants to be able to store anything, it holds its contents in an object array
This means you can put two completely unrelated things in next to each other, you have to inspect the type of them if you do, and you always have to cast to turn the object back into what you want
notiList.Add(123); //whoops, that's not a NotiObject
foreach(var o in notiList)
var n = (NotiObject)notiList[0]; //whoops, that's a crash
}
So, working with it is pretty wearisome, particularly the part where you have to cast all the time.. This gets boring very quickly:
object o = "hello";
object p = "world";
object q = (string)o + (string)p;
object r = ((string)q).Substring(3).IndexOf((stribg)p);
r = (int)r + ((int)r)/2;
Storing everything in an object can be done, but look at what a mess it is. You'd have to start putting the type name into the variable name just to help remember that r was an int, and q was a string - Hungarian notation's another relic of the past.
When you put things in an ArrayList, this is what you're doing; storing them in object
So generics were invented and List was invented. A list that can be custom made to store a single type of objects like a string, int or NotiObject
var nums = new List<int>();
nums.Add(123); //works
var notiList = new List<NotiObject>();
notiList.Add(123); //compiler refuses this one
Now I've said all that, it's possible to answer your question. This code doesn't make sense:
NotiObject randomNoti = notiList.IndexOf(i);
i is an integer. IndexOf is a method that finds the numeric index of an item in the list. If the list was "a","b","c" and you asked for IndexOf("b") the result is 1 because b is at the second index, and indexing starts from 0.
IndexOf is not "get me the object at index blahblah", it's "tell me the index of this object blahblah"
The code doesn't make sense because you've passed an integer in and the list stores NotiObject. IndexOf will never find an integer in a list of NotiObject. This was the first mistake. You were allowed to make it because ArrayList stores everything as objects so you're allowed to pass an integer into IndexOf even if there are no integers in the list
IndexOf returns an integer. You cannot assign an integer to a variable of type NotiObject. This is the thing the compiler is complaining about
Even if you form the code correctly, you still have to cast:
NotiObject randomNoti = (NotiObject)notiList[i];
It's all very wearisome and if you persist with ArrayList probably not the last mistake you'll make with it either
If you used a List<NotiObject> you wouldn't have been allowed to pass an integer to IndexOf; the compiler would have stopped you which would hopefully then have made you assess IndexOf in the docs, and see that it's for finding the int index from the object, not the object at int index
You'd write code like:
List<NotiObject> notiList = new List<NotiList>();
...
NotiObject randomNoti = notiList[i];
without the cast. If you want to read more into why there is no cast, check out some introductory articles to generics. In a nutshell generics (any time you see something like <T> or <TBlahBlah>) allow you to specify something like a template code skeleton that the compiler uses to create code for you; code that substitutes the for the kind of object you want to work with. There isn't any casting any more because the compiler will write a whole List class that dedicatedly only works with NotiObjects
After learning how to Create a method with infinite parameters, I wonder is it legal to store the parameter array into a array. Will it cause any problem, since I don't see many people use this approach.
Code below :
class Foo
{
private String[] Strings;
public Foo(params String[] strings)
{
Strings = strings;
}
...
}
That's fine - it's just an array.
All the compiler does with a parameter array is convert a call like this:
Foo("x", "y");
into:
Foo(new string[] { "x", "y" });
That's really all there is to it. Anything you'd expect to be appropriate with the second call is fine with a parameter array.
Arrays passed into public methods are rarely suitable to store directly due to all arrays being mutable - but that's a matter of how you handle mutable parameter types rather than being specific to parameter arrays.
I have a question about reversing the elements of a list in C#.
The ultimate goal is to get the last N elements of a list.
Suppose I have a list of decimals.
List<decimal> listOfDecimals = new List<decimal>() { 1.5m, 2.4m, 3.6m, 0.1m };
This is my attempt to get a list containing the last 2 elements of listOfDecimals.
List<decimal> listOfLastTwoElements = listOfDecimals.Reverse<decimal>().Take<decimal>(2).Reverse<decimal>().ToList<decimal>();
My question is, if I replaced Reverse<>() with Reverse(), there is a syntax error as flagged by VS.
Can anyone please let me know when I should use Reverse(), and when to use Reverse<>()?
This is because List itself has a Reverse method. This reverse method does not return anything.
The reverse method on List<T> takes precedence over the extension method on IEnumerable<T>.
Confusing is that when you just have an IEnumerable<T>, you can use Reverse() without type argument. Then the type inference of the compiler resolves the generic type argument. So the extension method looks the same as the method on List<T>.
var reversed1 = Enumerable.Empty<int>().Reverse(); // works
var reversed2 = Enumerable.Empty<int>().Reverse<int>(); // works and is the same as the line above.
var reversed3 = new List<int>().Reverse(); // does not work
var reversed4 = new List<int>().Reverse<int>(); // works
Reverse() is a method of List<T>, Reverse<T>() is a (extension)method of IEnumerable<T>, so that includes List<T>.
If you want to take the last 2 elements of an IEnumerable, you can just do Last(2). This will return an IEnumerable<T>, so if you want that in a List, you must call ToList on that.
List<T> also has a method `RemoveRange()`, so if you want to remove all but the last 2 elements:
listOfDecimals.RemoveRange(0, listOfDecimals.Count - 2)
When a List<> of primitive types is created in C# (e.g. a List<int>), are the elements inside the list stored by value, or are they stored by reference?
In other words, is C# List<int> equivalent to C++ std::vector<int> or to C++ std::vector<shared_ptr<int>>?
A List<int> will have an int[] internally. No boxing is required usually - the values are stored directly in the array. Of course if you choose to use the List<T> as a non-generic IList, where the API is defined in terms of object, that will box:
List<int> list1 = new List<int>();
// No boxing or unboxing here
list1.Add(5);
int x = list1[0];
// Perfectly valid - but best avoided
IList list2 = new List<int>();
// Boxed by the caller, then unboxed internally in the implementation
list2.Add(5);
// Boxed in the implementation, then unboxed by the caller
int y = (int) list2[0];
Note that the phrase "stored by reference" is a confusing one - the term "by reference" is usually used in the context of parameter passing where it's somewhat different.
So while a List<string> (for example) contains an array where each element value is a reference, in a List<int> each element value is simply an int. The only references involved are the callers reference to the List<int>, and the internal reference to the array. (Array types themselves are always reference types, even if the element type is a value type.)
Value types are stored by value. (e.g. primitives and structs) Reference types are stored by reference. (e.g. classes)
So what would happen if you wrote code like this:
struct MutableValueType
{
public int ChangableInt32;
}
static class Program
{
static void Main()
{
var li = new List<MutableValueType>();
li.Add(new MutableValueType());
li[0].ChangableInt32 = 42;
}
}
Will you modify a copy of your struct, or will you change the copy that is inside the List<>? Will the compiler warn you? I would like to try this.
I'm using a third party library. One of the methods requires passing an array via ref that will be populated with some info. Here's the definition for the method:
int GetPositionList(ref Array arrayPos)
How do I construct arrayPos so that this method will work? In the library's not so complete documentation it defines the method as such:
long GetPositionList(structSTIPosUpdate() arrayPos)
I've tried this but of course I'm getting errors:
System.Array position_list = new System.Array();
sti_position.GetPositionList(ref position_list);
Any ideas?
This is the Sterling Trader Pro ActiveX API, right? Did you create an Interop dll using tlbimp.exe? The GetPositionList API expects an array which will hold structs of type structSTIPositionUpdate. Normally an out modifier is used if the callee initializes the passed-in data, and ref if the data is to be initialized. According to the meaning of the API the modifier should be out, so that this should work:
structSTIPositionUpdate [] entries = new structSTIPositionUpdate[0]; // or null
num_entries_returned = GetPositionList(ref entries);
Alternatively, try creating an array of these structs which is big enough to hold the expected number of entries, then pass it to the function:
structSTIPositionUpdate [] entries = new structSTIPositionUpdate[100]; // say
num_entries_returned = GetPositionList(entries);
Update: If you are getting type mismatches with System.Array, try
System.Array entries = Array.CreateInstance(typeOf(structSTIPositionUpdate), N);
where N is the number of elements in the array.
To create an instance of an Array you can use the CreateInstance method:
Array a = Array.CreateInstance(typeof(Int32), 10);
GetPositionList(ref a);
The type, dimension and size of the array is something the library author should document. The GetPositionList may be badly designed and simply create a new Array for you essentially meaning that the library author should have used out instead of ref. In that case you can use a null array:
Array a = null;
GetPositionList(ref a);
You can use Array.CreateInstance
This may help you:
http://msdn.microsoft.com/en-us/library/szasx730%28VS.80%29.aspx
...although I don't understand why an object needs to have the "ref" keyword. Objects are passed by reference, so this should work anyway, without making use of the ref keyword. For arrays like int[] or string I understand this...
This works:
Array position_list = new int[]{1, 3, 5, 5,6};
sti_position.GetPositionList(ref position_list);
I also using Sterling Trader API. I use this code:
private structSTIPositionUpdate[] PositionList {
get {
Array arrayPos = null;
_position.GetPositionList(ref arrayPos);
return (structSTIPositionUpdate[]) arrayPos;
}
}