O
O
Ogoun Er2011-04-14 16:17:36
C++ / C#
Ogoun Er, 2011-04-14 16:17:36

C#. Is it possible to create a list of objects of a previously unknown type?

For example, there is such a class:


    public class Value<T>
    {
        public Value()
        {
        }

        public Value(T value)
        {
            this.value = value;
        }

        private T value;
        
    }


I want to make a collection out of it:

public class Values: List<Value<T>>


, where T is not known in advance, but the language does not allow doing so. How to implement something like this?

As a result, I want something like:


Values v=new Values();
v.Add(new Value<int>());
v.Add(new Value<string>());
v.Add(new Value<MyType>());

Answer the question

In order to leave comments, you need to log in

8 answer(s)
B
bleykher, 2011-04-14
@bleykher

It's hard to answer the question without an example of further use of the list.
1. Can do just create

List<object>
and shove whatever you want in there.
2. If you need to call some method for an object in the list, then you can inherit Value from the class containing the declaration of the desired method (BaseValue class) and create a list
List<BaseValue>
.

F
Fastto, 2011-04-14
@Fastto

Keeping objects of different types in the same list only makes sense if they inherit at least one common interface.
Suppose we decide to store all the forms of our application in the list - all forms have a common parent class, so we probably know the common methods. In this case, with objects of such a list, it will be reduced to this form:

Copy Source | Copy HTML
  1.  
  2. using System.Reflection;
  3.  
  4. // создаем наши формы
  5. List<object> objects = new List<object>();
  6. objects.Add( new Form1() );
  7. objects.Add( new Form1() );
  8. objects.Add( new Form2() );
  9. objects.Add( new Form3() );
  10.  
  11. //отображаем их
  12. foreach( object obj in objects )
  13. {
  14. Type t= obj .GetType();
  15. Type[] tIncomingParams = {};
  16.  
  17. MethodInfo methodInfo = type.GetMethod( "Show", tIncomingParams );
  18. methodInfo.Invoke( obj, null );
  19. }
  20.  

If you are interested in how to check the presence of a specific object of an unknown type in such a list, write.

J
Jamon, 2011-04-14
@Jamon

and than did not arrange normal ArrayList?

H
Hanhe, 2011-04-14
@Hanhe

This is possible by using covariance .
But with limitations:
Firstly, this is only possible in VS2010, the 2008 compiler does not support this. Specify the requirements for the framework on msdn, as far as I remember 3.5 sp1 is supported, although I may be wrong, and .net 4 is required for covariance.
Secondly, it will not be possible to parameterize the class with value types (for example, int).
Plus covariance imposes some other restrictions, which you can read about in the msdn link above.
Code example:

Copy Source | Copy HTML
  1. public interface IValue<out T>
  2. {
  3.     T Get();
  4. }
  5.  
  6. public class Value<T>:IValue<T>
  7. {
  8.     public T Get()
  9.     {
  10.         return default(T);
  11.     }
  12. }
  13.  
  14. public class Values: List<IValue<object>>
  15. {
  16.  
  17. }

Usage example:
Copy Source | Copy HTML
  1. var v = new Values();
  2. v.Add(new Value<string>());
  3. v.Add(new Value<object>());
  4.  
  5. //а вот так нельзя: v.Add(new Value<int>());
  6.  

B
burdakovd, 2011-04-14
@burdakovd

in Java it would be

List<Value<?>>

K
kk86, 2011-04-15
@kk86

Alternatively, use a list of type dynamic:
List x = new List();
Но по сути это то же, что и список Object'ов, только ещё медленнее работающий, но не требующий явного приведения типов в коде. Учтите, что использование dynamic может нанести ущерб производительности, т.к. за ним стоит рефлекшн. Пример:

Copy Source | Copy HTML
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Test
  4. {
  5.     class Program
  6.     {
  7.         public static void Main(string[] args)
  8.         {
  9.             List<dynamic> list = new List<dynamic>();
  10.             list.Add(1);
  11.             list.Add("sdfsdf");
  12.  
  13.             foreach (dynamic item in list)
  14.                 Write(item);
  15.  
  16.             Console.ReadKey(true);
  17.         }
  18.  
  19.         public static void Write(Int32 intValue)
  20.         {
  21.             Console.WriteLine("Int: " + intValue);
  22.         }
  23.         public static void Write(String stringValue)
  24.         {
  25.             Console.WriteLine("String: " + stringValue);
  26.         }
  27.     }
  28. }

D
dmomen, 2011-04-14
@dmomen

You are smart about something. What is wrong with a regular untyped list in this case?
List v = new List();
v.Add(new Value());
v.Add(new Value());
v.Add(new Value());

S
Shedal, 2011-04-15
@Shedal

If it is not known in advance what types the elements will be, and at the same time they will need to be exported to some format, then converters are written for all standard types, and for the rest it is assumed that they must implement some kind of interface.
For example, like this:

protected Dictionary<Type, IExporter> Exporters { get; set; }

public void Export(object value, StreamWriter writer)
{
  IExporter exporter = FindExporter(value.GetType());
  
  if (exporter != null)
  {
    exporter.Export(value, writer);
  }
  else
  {
    writer.WriteString(value.ToString());
  }
}

private IExporter FindExporter(Type type)
{
  IExporter exporter = null;
  
  if(Exporters.ContainsKey(type))
  {
    exporter = Exporters[type];
  }
  else
  {
    if(typeof(IMyFormatExportable).IsAssignableFrom(type))
    {
      exporter = new ExportAwareExporter(type);
    }
  }
  
  return exporter;
}

And for your classes that you want to export manually, you implement the following interface:
public interface IMyFormatExportable
{
  void Export(StreamWriter writer);
}

public MyClass : IMyFormatExportable
{
  // ...
  
  void Export(StreamWriter writer)
  {
    // writer.Write...(...);
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question