Multiple objects in list, C# - c#

I'm looking for something similar to List<T>, that would allow me to have multiple T. For example: List<TabItem, DataGrid, int, string, ...> = new List<TabItem, DataGrid, int, string, ...>().

If you are using .NET 4, you could have a List<Tuple<T1, T2, ...>>
Otherwise, your choice is to implement your own type.

Create a class that defines your data structure, and then do
var list = new List<MyClass>();

Normally you'd just have List<MyClass> where MyClass had all those other ones as members.

If it can have any old type, then you need to use an ArrayList.
If you know ahead of time what you'll have in there, then you should either create your own structure, or use a Tuple.

Looks like you're after List<object>?

Tuples are best if you are using .net 4.0. But if you are working 3.5 or below, multidimensional object array is good. Here is the code. I have added 3 different types in a object array and I pushed the same to list. May not be the best solution for your question, can be achieved with object array and list. Take a look at the code.
class Program
{
static void Main(string[] args)
{
object[,] OneObject = new object[1,3]{ {"C Sharp",4,3.5 }};
List<object> MyList = new List<object>();
MyList.Add(OneObject);
object[,] addObject = new object[1,3]{{"Java",1,1.1}};
MyList.Add(addObject);
foreach(object SingleObject in MyList)
{
object[,] MyObject = (object[,])SingleObject;
Console.WriteLine("{0},{1},{2}", MyObject[0, 0], MyObject[0, 1], MyObject[0, 2]);
}
Console.Read();
}
}

Instead of trying in C# 4, you can give the old version features a chance here.
It seems you don't need a strongly typed collection here, in that case ArrayList is the best option.

Related

C# List<string[]> to List<object[]> Conversion

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();

C# Defined Arrays

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

C# Dynamic Cast with Reflection and Lists

since yesterday i'm working on a problem and i don't get it yet...
I've got a class with many Methods and decide in Runtime wich Method has to be called. Every of this Methods returns a List with Elements from my Businessobjects.
My Class looks this way:
public class ReflectiveClass {
public List<BO1> DoSomethingWithBO1(int param){
List<BO1> list = new List<BO1>();
//....
return list;
}
public List<BO2> DoSomethingWithBO2(int param){
List<BO2> list = new List<BO2>();
//....
return list;
}
public void Process(){
//...get MethodInfo and so on
List<object> myReturnValue = (List<object>)methodInfo.Invoke(this, new object[]{param});
// here comes the Exception
}
}
So, at Invoking the Method i got a
InvalidCastException
and the Debugger told me he could not Cast from
System.Collections.Generic.List`1[BO1]
to
System.Collections.Generic.List`1[System.Object]
I wonder why this doesn't work. I thougt if i use a List every Object could be in this List.
I've even tried it with List but same behaviour.
Is it possible to read reflective the Type of the Return-Value of a Method? And can i then create a Generic List with this Returnvalue and cast to this List? This would be wonderfull.
Greetings and many Thanks for your Help!
Benni
Obviously BO1 derives from Object, and you can't cast List<Derived> to List<Base>. Suppose we have:
List<Apple> apples = AListOfApples();
List<Fruit> fruits = (List<Fruit>)apples; //suppose it's valid to cast
fruits.Add(new Orange()); //Of course we can add an Orange to the list of Fruit
//Now you can see the list of Apple has an Orange in it!!
You can use IEnumerable<T> instead.
If you have behaviour that changes and is determined at runtime, it's ideal for the Strategy pattern. Have a look at http://www.dofactory.com/Patterns/PatternStrategy.aspx
List<_> needs to be invariant to be statically type-safe. Imagine this compiled
var strlist = List<string> { "blub" };
var olist = (List<object>)strlist;
Up to this point everything is nice and dandy, but if you now tried to write to
the list like so
olist.Add(3);
the runtime would have to throw an exception as the underlying array is not an int array, but a string array. That's why it does not compile in the first place.
Note that contary to generic lists, arrays have been covariant since C# 1.0,
probably for Java compatibility. So this indeed compiles:
string[] strlist = new[] { "huhu" };
var olist = (object[])strlist;
olist[0] = 3;
... but throws an exception at runtime.
IEnumerable<out T> is covariant in T in C# 4.0 (therefore the out). Maybe this would be the more appropriate interface for your purposes.
You can use this :
object myReturnValue = mi.Invoke(this, new object[] { });
MethodInfo miToList = typeof(Enumerable).GetMethod("ToList");
MethodInfo miListObject = miToList.MakeGenericMethod(new[] { typeof(object) });
List<object> listObject = (List<object>)miListObject.Invoke(myReturnValue, new object [] { myReturnValue });
You should really split your class into two different classes, that should implement same interface. Using reflaction here is not a good thing.
Or if you methdods differ only in type of input parameters, make them generic.
Well the only solution is to create a new list..
public void Process(){
//...get MethodInfo and so on
List<object> myReturnValue = new List<object>(((IList)methodInfo.Invoke(this, new object[]{param})).ToArray());
// here comes no Exception!
}
I appreciate all the Answers!
For your information: I've implemented the Strategy Pattern, because it fits really good to my Project.
PS: I love this community, the peoble here help you so quick and with good solutions. Thanks!

how to add an associative index to an array. c#

i have an array of custom objects. i'd like to be able to reference this array by a particular data member, for instance myArrary["Item1"]
"Item1" is actually the value stored in the Name property of this custom type and I can write a predicate to mark the appropriate array item. However I am unclear as to how to let the array know i'd like to use this predicate to find the array item.
I'd like to just use a dictionary or hashtable or NameValuePair for this array, and get around this whole problem but it's generated and it must remain as CustomObj[]. i'm also trying to avoid loading a dictionary from this array as it's going to happen many times and there could be many objects in it.
For clarification
myArray[5] = new CustomObj() // easy!
myArray["ItemName"] = new CustomObj(); // how to do this?
Can the above be done? I'm really just looking for something similar to how DataRow.Columns["MyColumnName"] works
Thanks for the advice.
What you really want is an OrderedDictionary. The version that .NET provides in System.Collections.Specialized is not generic - however there is a generic version on CodeProject that you could use. Internally, this is really just a hashtable married to a list ... but it is exposed in a uniform manner.
If you really want to avoid using a dictionary - you're going to have to live with O(n) lookup performance for an item by key. In that case, stick with an array or list and just use the LINQ Where() method to lookup a value. You can use either First() or Single() depending on whether duplicate entries are expected.
var myArrayOfCustom = ...
var item = myArrayOfCustom.Where( x => x.Name = "yourSearchValue" ).First();
It's easy enough to wrap this functionality into a class so that external consumers are not burdened by this knowledge, and can use simple indexers to access the data. You could then add features like memoization if you expect the same values are going to be accessed frequently. In this way you could amortize the cost of building the underlying lookup dictionary over multiple accesses.
If you do not want to use "Dictionary", then you should create class "myArrary" with data mass storage functionality and add indexers of type "int" for index access and of type "string" for associative access.
public CustomObj this [string index]
{
get
{
return data[searchIdxByName(index)];
}
set
{
data[searchIdxByName(index)] = value;
}
}
First link in google for indexers is: http://www.csharphelp.com/2006/04/c-indexers/
you could use a dictionary for this, although it might not be the best solution in the world this is the first i came up with.
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("cat", 2);
d.Add("dog", 1);
d.Add("llama", 0);
d.Add("iguana", -1);
the ints could be objects, what you like :)
http://dotnetperls.com/dictionary-keys
Perhaps OrderedDictionary is what you're looking for.
you can use HashTable ;
System.Collections.Hashtable o_Hash_Table = new Hashtable();
o_Hash_Table.Add("Key", "Value");
There is a class in the System.Collections namespace called Dictionary<K,V> that you should use.
var d = new Dictionary<string, MyObj>();
MyObj o = d["a string variable"];
Another way would be to code two methods/a property:
public MyObj this[string index]
{
get
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
return o;
}
}
}
set
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
var i = My_Enumerable.IndexOf(0);
My_Enumerable.Remove(0);
My_Enumerable.Add(value);
}
}
}
}
I hope it helps!
It depends on the collection, some collections allow accessing by name and some don't. Accessing with strings is only meaningful when the collection has data stored, the column collection identifies columns by their name, thus allowing you to select a column by its name. In a normal array this would not work because items are only identified by their index number.
My best recommendation, if you can't change it to use a dictionary, is to either use a Linq expression:
var item1 = myArray.Where(x => x.Name == "Item1").FirstOrDefault();
or, make an extension method that uses a linq expression:
public static class CustomObjExtensions
{
public static CustomObj Get(this CustomObj[] Array, string Name)
{
Array.Where(x => x.Name == Name).FirstOrDefault();
}
}
then in your app:
var item2 = myArray.Get("Item2");
Note however that performance wouldn't be as good as using a dictionary, since behind the scenes .NET will just loop through the list until it finds a match, so if your list isn't going to change frequently, then you could just make a Dictionary instead.
I have two ideas:
1) I'm not sure you're aware but you can copy dictionary objects to an array like so:
Dictionary dict = new Dictionary();
dict.Add("tesT",40);
int[] myints = new int[dict.Count];
dict.Values.CopyTo(myints, 0);
This might allow you to use a Dictionary for everything while still keeping the output as an array.
2) You could also actually create a DataTable programmatically if that's the exact functionality you want:
DataTable dt = new DataTable();
DataColumn dc1 = new DataColumn("ID", typeof(int));
DataColumn dc2 = new DataColumn("Name", typeof(string));
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
DataRow row = dt.NewRow();
row["ID"] = 100;
row["Name"] = "Test";
dt.Rows.Add(row);
You could also create this outside of the method so you don't have to make the table over again every time.

Retrieving items from an F# List passed to C#

I have a function in C# that is being called in F#, passing its parameters in a Microsoft.FSharp.Collections.List<object>.
How am I able to get the items from the F# List in the C# function?
EDIT
I have found a 'functional' style way to loop through them, and can pass them to a function as below to return C# System.Collection.List:
private static List<object> GetParams(Microsoft.FSharp.Collections.List<object> inparams)
{
List<object> parameters = new List<object>();
while (inparams != null)
{
parameters.Add(inparams.Head);
inparams = inparams.Tail;
}
return inparams;
}
EDIT AGAIN
The F# List, as was pointed out below, is Enumerable, so the above function can be replaced with the line;
new List<LiteralType>(parameters);
Is there any way, however, to reference an item in the F# list by index?
In general, avoid exposing F#-specific types (like the F# 'list' type) to other languages, because the experience is not all that great (as you can see).
An F# list is an IEnumerable, so you can create e.g. a System.Collections.Generic.List from it that way pretty easily.
There is no efficient indexing, as it's a singly-linked-list and so accessing an arbitrary element is O(n). If you do want that indexing, changing to another data structure is best.
In my C#-project I made extension methods to convert lists between C# and F# easily:
using System;
using System.Collections.Generic;
using Microsoft.FSharp.Collections;
public static class FSharpInteropExtensions {
public static FSharpList<TItemType> ToFSharplist<TItemType>(this IEnumerable<TItemType> myList)
{
return Microsoft.FSharp.Collections.ListModule.of_seq<TItemType>(myList);
}
public static IEnumerable<TItemType> ToEnumerable<TItemType>(this FSharpList<TItemType> fList)
{
return Microsoft.FSharp.Collections.SeqModule.of_list<TItemType>(fList);
}
}
Then use just like:
var lst = new List<int> { 1, 2, 3 }.ToFSharplist();
Answer to edited question:
Is there any way, however, to reference an item in the F# list by index?
I prefer f# over c# so here is the answer:
let public GetListElementAt i = mylist.[i]
returns an element (also for your C# code).

Categories

Resources