I am working with some existing C# code. Essentially, I have a variable which is a List of objects.
Each of the objects, in turn is a string[n]. I know n, and the value is the same for all the objects in the list. What I need to know is how to loop over the list of objects and get, for each item, a
string[n]
I read your question as how to cast an object of compile time type Object to its run time type of string[]. You do that like so:
Object obj = ...;
string[] arr = (string[]) obj;
What about just casting the object to string[]?
string[] arr = (string[])listOfObjects[x];
It sounds like you want the Cast method:
foreach(string[] strings in listOfStringArrays.Cast<string[]>())
{
// ...
}
Use Enumerable.SelectMany. It projects each element of a sequence to an IEnumerable and flattens the resulting sequences into one sequence.
var resultantArray = myarray.SelectMany(x => x).ToArray();
Related
I have a question about Enumerable.Repeat function.
If I will have a class:
class A
{
//code
}
And I will create an array, of that type objects:
A [] arr = new A[50];
And next, I will want to initialize those objects, calling Enumerable.Repeat:
arr = Enumerable.Repeat(new A(), 50);
Will those objects have the same address in memory?
If I will want to check their hash code, for example in that way:
bool theSameHashCode = questions[0].GetHashCode() == questions[1].GetHashCode();
This will return me true, and if I will change one object properties, all other objects will change it too.
So my question is: is that properly way, to initialize reference type objects? If not, then what is a better way?
Using Enumerable.Repeat this way will initialize only one object and return that object every time when you iterate over the result.
Will those objects have the same address in memory?
There is only one object.
To achieve what you want, you can do this:
Enumerable.Range(1, 50).Select(i => new A()).ToArray();
This will return an array of 50 distinct objects of type A.
By the way, the fact that GetHashCode() returns the same value does not imply that the objects are referentially equal (or simply equal, for that matter). Two non-equal objects can have the same hash code.
Just to help clarify for Camilo, here's some test code that shows the issue at hand:
void Main()
{
var foos = Enumerable.Repeat(new Foo(), 2).ToArray();
foos[0].Name = "Jack";
foos[1].Name = "Jill";
Console.WriteLine(foos[0].Name);
}
public class Foo
{
public string Name;
}
This prints "Jill". Thus it shows that Enumerable.Repeat is only creating one instance of the Foo class.
When using the following code to create an array:
var foos = Enumerable.Repeat(new Foo(), 2).ToArray();
The reason why each location in the array is the same is because you are passing an object, and not a function that creates an object, the code above is the same as:
var foo = new Foo();
var foos = Enumerable.Repeat(foo , 2).ToArray();
The reason above also explains why using a Select statement, like in the code below, creates a new object for each entry, because you are passing a function that dictates how each object is created, rather than the object itself.
Enumerable.Range(1, 2).Select(i => new Foo()).ToArray();
I would use a simple for loop to populate an array with new reference types.
I've got a little code that pulls a boxed ienumerable instance out of an expression tree. The code needs to convert it into object[].
So far I've gotten away with assuming it'll be IEnumerable<string> and thus casting it followed with .ToArray().
Circumstances have changed and now it could also possibly be a IEnumerable<int>. I still need to change the box into an object[] and don't really care what the type is.
object list = Expression.Lambda(methodCallExpression.Object).Compile().DynamicInvoke();
var enumerable = (IEnumerable<string>)list;
object[] values = enumerable.ToArray();
UPDATE:
Strings are references and Integers are value types. I've found that while I can box the reference to an array of ints, I cannot pretend it's an array of boxed ints as int's cannot be boxed.
An exception of type 'System.InvalidCastException' occurred in
System.Core.dll but was not handled in user code Additional
information: Unable to cast object of type
'System.Collections.Generic.List1[System.Int32]' to type
'System.Collections.Generic.IEnumerable1[System.Object]'.
object list = Expression.Lambda(methodCallExpression.Object).Compile().DynamicInvoke();
var enumerable = (IEnumerable<object>)list;
object[] values = enumerable.ToArray();
Just call Cast before ToArray:
object[] values = enumerable.Cast<object>().ToArray();
Note that this casts each item, not the entire collection. You can't "cast" a collection of ints to a collection of objects, you have to convert each item to an object (i.e. box them).
Previously answered in Best way to convert IList or IEnumerable to Array.
Or you could do it the hard way:
IEnumerable enumberable = (IEnumerable)list;
List<object> values = new List<object>();
foreach (object obj in enumerable)
{
values.Add(obj);
}
Haven't tested it, but you could theoretically cast it to IEnumerable<object> using Linq:
object [] values = ((IEnumerable)list).Cast<object>().ToArray();
I have this line of code:
Dictionary<string,string> alreadyThere = GetItFromFooMethod();
List<string> flatList = alreadyThere.Values.SelectMany(a => a).ToList();
But I get this compile error:
Cannot implicitly convert type 'System.Collections.Generic.List<char>' to 'System.Collections.Generic.List<string>'
Why does it think I need char? and how can I fix it?
I think you just want to get the Values like this:
List<string> flatList = alreadyThere.Values.ToList();
Since string is an IEnumerable<char>, SelectMany returns IEnumerable<char>. It thinks that you are trying to get each character separately into a list. But I don't think you want that..
Flattening can be useful only if you have a IEnumerable<IEnumerable<T>> for example if you would have a Dictionary<string, List<string>> then that code would work.But in your case the Values collection is already an IEnumereable<string>,so calling ToList should be enough...
All, have I gone mental (this is not the question). I want to convert List<string[]> to List<object[]>
List<string[]> parameters = GetParameters(tmpConn, name);
List<object[]> objParams = parameters.OfType<object[]>();
this is not working, but unless I have forgotten something a conversion using this method should be possible (no Lambdas needed)?
Thanks for your time.
You want to use something like:
List<object[]> objParams = parameters.OfType<object[]>().ToList();
or in C# 4.0, just
List<object[]> objParams = parameters.ToList<object[]>();
or
List<object[]> objParams = parameters.ConvertAll(s => (object[])s);
Because of array covariance, in .NET 4.0, you can just do:
// Works because:
// a) In .NET, a string[] is an object[]
// b) In .NET 4.0, an IEnumerable<Derived> is an IEnumerable<Base>
var result = parameters.ToList<object[]>();
But note that you wouldn't be able to mutate those arrays with anything other than strings (since array covariance isn't truly safe).
If you want truly flexible writable object arrays, you can do:
var result = parameters.Select(array => array.ToArray<object>())
.ToList();
(or)
var result = parameters.ConvertAll(array => array.ToArray<object>());
Then you could replace the elements of each inner array with instances of pretty much any type you please.
OfType<string[]> returns an IEnumerable<string[]>, not a List<object[]>.
Enuemrable.OfType filters out any invalid casts. You may want to consider Enumerable.Cast instead ,which will throw if you make a mistake. If string[] doesn't inherit from object[] (I honestly don't remember), you may need to call Enumerable.Select to provide a conversion.
You definately need a Enumerable.ToList call in there somewhere.
How about doing it this way
List<string[]> sList = new List<string[]> {new []{"A", "B"}};
List<object[]> oList = sList.Cast<object[]>().ToList();
Can I define an array such that the first element is String, the Second is an int and the third is a textbox?
It's like when we create a List we choose type of element List<string >
Update from Comment:
Sorry I couldnt explain.I need to like
this List<string,int,object> Firstly i
will set type and when i call the list
i will not need to cast
thanks
create list of objects. in C# everything is derived from object
List<object> list = new List<object> {"first", 10, new TextBox()};
EDIT(To comment):
Then you should create seperate class to hold those three items , or use Tuple
List<Tuple<string,int,TextBox>> list;
You can declare an array of object and do that. You're talking about a mixed type array, right?
var arr = new object[] { "Hi", 42, 3.7, 'A' }
If you need an array that has elements without a common base-class other than object, then you're going to need an array of objects!
object[] myArray = new object[] { "Hi", 23, new TextBox() };
Note that this is not really something you should doing. If you need to associate disparate types like this, a class makes much more sense.
You want a Tuple<string,int,TextBox>, not an array.
IMHO the best way to do this is through a List<> of objects:
String s = "hey!";
int i = 156;
TextBox t = new TextBox();
List<object> list = new List<object>(3);
list.Add(s);
list.Add(i);
list.Add(t);
The reason this works is because (almost?) everything in C# derives from the base-class object
Arrays are typically homogeneous collections, which means that every object contains in the array is of the same type (or at least shares a common parent type). An array of [string, int, textbox] could be defined as an object[] but that's really misuse of arrays.
Just create a proper class which contains the 3 fields.
class MyType {
public string myString;
public int myInt;
public Listbox myListbox;
}
If you're looking make a list of string, int, textbox, you can either create a class which has those members or look at the Tuple class in .net 4.0
List<Tuple<string,int,TextBox>
Define a class that contains the 3 types then define an array that contains the new type.
Object[] myObjects = new Object(){"myString", 42, textbox1};
System.Collections.Generic.Dictionary<string, object> source = new System.Collections.Generic.Dictionary<string, object>();
source.Add("A", "Hi");
source.Add("B", 10);
source.Add("C", new TextBox());
While accessing
string str = Convert.ToString(source["A"]);
int id = Convert.ToInt16(source["B"]);
TextBox t = (TextBox)source["C"];
I will suggest that you create a Type such as
enum ItemType { Int, String, Textbox }
class MyType {
public object objValue;
public ItemType itemType;
}
List<MyType> list = new List<MyType>();
.......
You can iterate through the list or extract the list by type such as below.
var intList = list.Where(e=>e.itemType == ItemType.Int);
Of course you can achieve the above with the enum and using the reflected Type info directly from the object, but I just think it is clearer this way also more explicitly list out the type your list can hold rather than just all type in the CLR