Initialize generic object with unknown type - c#

How can I initialize a list containing generic objects whose types can be different?
For example, I have the following:
this.Wheres = new List<Where<>>();
As you know, <> is not valid syntax. However, sometimes the type passed to Where will be a string and sometimes it will be DateTime, etc. I tried using object as the initialized type, but that doesn't work either.

Well, you haven't really given enough context (what's SqlWhere?) but normally you'd use a type parameter:
public class Foo<T>
{
private IList<T> wheres;
public Foo()
{
wheres = new List<T>();
}
}
If you want a single collection to contain multiple unrelated types of values, however, you will have to use List<object>

this.Wheres = new List<Object>();

Related

How to cast an IEnumerable<object> to an IEnumerable<runtime type>

I'm trying to accomplish the following.
Suppose I have this data model:
public class Article
{
public ICollection<string> Tags { get; set; }
}
These tags are retrieved from a database. My database's API returns them to me as a List<object>.
Therefore, I need to make a conversion from List<object> to something that implements ICollection<string>.
I am aware of the LINQ Cast<T>() method that cast its elements to the given type and returns the converted IEnumerable<T>.
However, I cannot use Cast<string>() because that would always cast my List<object> to IEnumerable<string>, not giving any options for models that have ICollection<double> properties (or any other type).
I can use reflection and get the generic type parameter:
Type genericArg = collectionType.GetGenericArguments().First();
But that would leave me with a runtime Type, which I cannot use as Cast<genericArg>().
How can I cast an IEnumerable<object> to an IEnumerable of a dynamic Type?.
I should note that no complex types are allowed on my model, so anything like:
public ICollection<Tag> Tags { get; set; }
will not happen. I only handle primitive types.
You have a basic misunderstanding about casting.
The result type of a casting operation must be known at compile time.¹
Consider the following example:
string a = "abc";
object b = (object)a;
string c = (string)b;
The runtime type of a, b and c is the same. It's string. The compile-time type is different. Casting is only relevant for the compile-time type.
Thus, the answer to your question
How to cast an IEnumerable<object> to an IEnumerable<runtime type>
is: You don't. Casting does not make sense for runtime types.
That said, let me offer a solution to your real problem: Let's say you have an IEnumerable<object> values, a Type myTargetType and want to create a List<typeof(myTargetType)> containing the values.
First, you create the list using reflection:
var listType = typeof(List<>).MakeGenericType(myTargetType);
IList myList = (IList)Activator.CreateInstance(listType);
And then you fill the list:
foreach (var item in values)
{
myList.Add(item);
}
Obviously, Add will throw an ArgumentException if an entry of values is not of runtime type myTargetType.
¹ The result type can be a generic type, but generic type parameters have to be specified at compile time as well.
I believe System.Convert has what you need:
Type genericArg = collectionType.GetGenericArguments().First();
foreach(var obj in collection) {
yield return Convert.ChangeType(obj, genericArg);
}
Enumerable.Cast<T>(this IEnumerable source) is normally what you'd be looking for. It is possible to use reflection to close the generic type yourself if different variations are required:
class Program
{
static void Main(string[] args)
{
var source = new List<object> {
"foo",
"bar",
"baz"
};
var type = typeof(string); // or however you find out the type
var castMethod = typeof(Enumerable)
.GetMethod("Cast").MakeGenericMethod(
new[] {
type
});
var result = (IEnumerable<string>)
castMethod.Invoke(null, new object[] {source});
foreach (var str in result)
{
Console.WriteLine(str.ToUpper());
}
}
}
The other problem is that it is not meaningful to cast from one List<T> to another - the generic parameter is invariant, because the collection is read-write. (Arrays allow some such casting for historical reasons.) If you're only reading, though, the IEnumerable<T> returned from Cast is sufficient.
You need to implement a generic method which take result from your database api and return appropriate collection as per your model, something like below:
private ICollection<T> RetrieveTags()
{
// Get tags using database api
return tags.Cast<T>();
}
Then call this method to get model as needed, for example:
ICollection<int> t1 = RetrieveTags<int>();
ICollection<string> t2 = RetrieveTags<string>();

Casting a collection's generics implicitly

Last night I learned about this wonderful operation of casting by example: a very cool way to generate a collection of some Type using a reference to an existing instance.
My problem is that although this works when you explicitly create the instance, the Type of collection produced is inaccurate if you use activator to instantiate from a Type.
class TestCollectionContent
{
public int id { get; private set; }
}
[Test]
public void TestListCastCreation()
{
var explicitCast = new TestCollectionContent (); //This casts as TestCollectionContent
var explicitList = MakeList (explicitCast); //This casts as List<CommandWithExecute>
explicitList.Add (new TestCollectionContent ());
Type clazz = typeof(TestCollectionContent);
var implicitCast = Activator.CreateInstance (clazz);//This casts as TestCollectionContent
var implicitList = MakeList (implicitCast); //This casts as List<object>
implicitList.Add (new TestCollectionContent ());
Assert.AreEqual (explicitCast.GetType (), implicitCast.GetType ()); //Succeeds
Assert.AreEqual (explicitList.GetType (), implicitList.GetType ()); //FAILS!
}
public static List<T> MakeList<T>(T itemOftype)
{
List<T> newList = new List<T>();
return newList;
}
For my purpose it is imperative that the collection be correctly cast. Any thoughts?
Note that I'm using C# with Unity3D (which uses something akin to .Net 3.5).
Activator.CreateInstance always returns an object, so you will not get any static type information from it when using it. This will make the variable implicitCast of type object although its value is of a more specialized type.
Now when using generics, only the type that is available for static typing is taken into account. So when passing implicitCast to MakeList, all that method sees is an object. As such, the method will be called as MakeList<object> and will return a List<object>, which is of course not of the same type as explicitList.
Unfortunately (or fortunately?) you cannot really do this any better. Generics are supposed to be something for use in a static typing environment, and if you start to create types dynamically, you will lose this ability.
You could however use Activator.CreateInstance for the list creation just as well by doing something like this:
public static IList MakeList(object itemOftype)
{
Type listType = typeof(List<>).MakeGenericType(itemOfType.GetType());
return (IList) Activator.CreateInstance(listType);
}
Of course, this will also just return an object, so you will have to cast it to a more specialized type, or use the non-generic IList interface to have at least some access to it.
This code behaves this way because T is inferred at compile time, not run time. Since implicitCast is of type object, it compiles with MakeList<object>.
var implicitList = MakeList (implicitCast); // equivalent to
List<object> implicitList = MakeList<object>(implicitCast);
var explicitList = MakeList (explicitCast); // equivalent to
List<TestCollectionContent> explicitList =
MakeList<TestCollectionContent>(explicitCast);
If you want it to use the runtime type, you can use reflection or dynamic.

Checking Type Inside Collection in C#

I am kind of new to C# and not sure about the following:
I have a parameter defined as follows:
public Collection<object> InputObject
{
get { return inputObject; }
set { inputObject= value; }
}
private Collection<object> inputObject;
As you can see, the object is a collection of objects since I am expecting different types.
When later I want to check the type, what is the right way?
I tried this:
if (inputObject is Collection<MyDefinedObject>)
{
}
but I get an underlined warning that the given expression is never of the expected type. What is the right way to check for a type within a collection?
Thanks
You have a collection of Object
When you write
Collection<object>
that means you are defining a collection that can contain any object.
When you do that, you can then do something like
inputObject.Add(new MyDefinedObject());
inputObject.Add(new StringBuilder()));
and you end up with different types in your collection.
Checking specific elements of your collection
If you want to test the type of a specific object in that collection you could so something like
Type t = inputObject[0].GetType();
or
if (inputObject[0] is MyDefinedObject)
The code
if (inputObject is Collection<MyDefinedObject>)
will never be true because you already defined
private Collection<object> inputObject;
meaning you defined the type of the collection inputObject to be Collection<object>
What if I want everything in the collection to be MyDefinedObject?
Based on your comments below your question, this is what you really want...
private Collection<MyDefinedObject> inputObject;
The Error Message You are Getting
but I get an underlined warning that the given expression is never of the expected type
That is because inputObject is of type Collection<object>, which is never of type Collection. That's like saying an apple is never a banana.
A Better Approach
If you are using generics and receiving a generic collection, why not create a generic function to process that collection too?
private void ProcessCollection<T>(Collection<T> inputObject)
{
}
// Somewhere else in your code...
Collection<MyDefinedObject> inputObject = // Initialize this however you do now
ProcessCollection<MyDefinedObject>(inputObject);
Since your Collection<> contains object, the collection has (in essence) no type. You either give the collection an actual type, or you check the items IN the collection for a type.
All object inherits the base class object, then you can use :
if(InputObject[0].GetType()==typeof(string)){
//string is an example and 0 can be replaced with a index
}
to know which type is each object
You are going to need to check all. The collection is defined as object
foreach (object obj in InputObject)
{
obj.gettype();
if (obj is DocFieldEnumHierTwoSpeedLoader) x= 5;
}
Perhaps this is what you want:
var defined = InputObject.OfType<MyDefinedObject>();
var other = InputObject.OfType<MyOtherDefinedObject>();
bool hasDefined = defined.Any();
bool hasOther = other.Any();
You say that the inputObject property can contain collections whose collection type can vary from time to time. There are two solutions:
1) If the type of the collection's elements is always the same for a given instance of the type that defines the property, make that type generic:
public class MyClass<T>
{
public Collection<T> InputObject
{
get { return inputObject; }
set { inputObject= value; }
}
private Collection<T> inputObject;
}
If the same instance of the property could hold collections with varying element types, then declare the field as object, or, perhaps better, as a non-generic interface type:
public class MyClass
{
public ICollection InputObject
{
get { return inputObject; }
set { inputObject= value; } // you should add some type checking here
//to make sure an invalid collection type isn't passed in
}
private ICollection inputObject;
public Collection<T> GetTypedCollection<T>()
{
return (Collection<T>)inputObject;
}
}
The GetTypedCollection method requires that you know at compile time what the collection's type is; if that's not possible, you'll need to post more sample code so we can suggest a solution.

Typed<>/untyped design

I have an (existing) typed class of items:
Items<T>
T Value { get; }
T can be double, string or int.
I then have a class that has to hold several instances of Items. Within a single instance of this class, T is always the same. As it stands, the type actually contained is determined by a property and the container is not typed:
Data
DataType { get; set; }
Items<double>
double Value;
Items<string>
// ... and so on. Nasty stuff.
Ideally, of course, this would be
Data<T>
Items<T>
T value
Data instances are created from scratch in code, and can be loaded from a database. So of course a factory would be in our future, but what is the return type of the Create method?
Even worse, I need this:
DataCollection
// HERE'S THE PAIN: What's the type here?
List of Data<> instances with differing types
foreach (? data in someDataCollection)
if (thetypeof data is double)
doSomething();
else
doSomethingElse();
Now, I can solve this, but I can't see a CLEAN way to solve this.
My first issue is the declaration of DataCollection. What is the type of the list? List<object>, so it can hold Data<double> and Data<string>?
There actually is a clean way to solve this; you can use a Dictionary with keys of the data type and values which are of type generic Func<> . You then pass the type to your create method, which then looks up the Func<> to use in the Dictionary based on the type, and invokes that Func<> to create or process your object.
Since I am working from pseudo code, basically it would look something like the below; you can play with it and modify it to get it to serve your needs, but this is the basic idea.
First, create a parent class for all data objects; note that this class has a lookup dictionary for functions to invoke on various types, and note that it is abstract:
public abstract class Data
{
// A Lookup dictionary for processing methods
// Note this the functions just return something of type object; specialize as needed
private static readonly IDictionary<Type, Func<object, Data>> _processFunctions = new Dictionary
<Type, Func<object, Data>>()
{
{typeof(int), d => { return doSomethingForInt( (Data<int>) d); }},
{typeof(string), d => { return doSomethingForString( (Data<string>) d); }},
{typeof(double), d => { return doSomethingForDouble( (Data<double>) d); }},
};
// A field indicating the subtype; this will be used for lo
private readonly Type TypeOfThis;
protected Data(Type genericType)
{
TypeOfThis = genericType;
}
public Data Process()
{
return _processFunctions[this.TypeOfThis](this);
}
}
Now subclass Data with a generic type that can be instantiated:
class Data<T> : Data
{
// Set the type on the parent class
public Data() : base(typeof(T))
{
}
// You can convert this to a collection, etc. as needed
public T Items { get; set; }
public static Data<T> CreateData<T>()
{
return new Data<T>();
}
}
You can then create a DataCollection class using the parent type. Note the ProcessData() method; all it does now is loop over the elements and call Process() on each one:
class DataCollection
{
public IList<Data> List = new List<Data>();
public void ProcessData()
{
foreach (var d in List)
{
d.Process();
}
}
}
...and you're all set! Now you can invoke your DataCollection with different types of Data:
DataCollection dc = new DataCollection();
dc.List.Add(new Data<int>());
dc.List.Add(new Data<string>());
dc.List.Add(new Data<double>());
dc.ProcessData();
I think every time you need to do if-conditions on runtime data type, it means there's something wrong with the data structures. But every time I encounter situation like this, I have a hard time to solve it.
What I would try to do here is to wrap your primitive types into some kind of Adapters with conversion methods (possibly even implicit) and make all of them implement a common interface, let's say IDoSomething. Then, you can define the doSomething behaviors in IntWrapper, DoubleWrapper etc. separately. Then your DataCollection should be of type List<IDoSomething> and the loop can just call data.DoSomething() method from the interface.
Having implicit conversion allows you to use the collection in the natural way like data.Add(3) - you'll still be able to add the items without wrapping the privitives

is this possible: c# collection of Type with constrains, or collection of generic type?

I'm trying to store types in a collection, so that i can later instantiate objects of the types in the collection. But I'm not sure how to do this the best way.
What i have so far:
List<Type> list = new List<Type>();
list.Add(typeof(MyClass));
var obj = (MyClass)Activator.CreateInstance(list[0]);
I would like to have some constrains on the Type, or better yet, just a generic type in the collection instead of an instantiated Type object. Is this possible?
That's not how generic collection constraints work.
Generic constraints restrict which types are legal for instantiating a generic type. There are several different kinds of constraints, but the common ones limit a generic parameter to either inherit or be an instance of a given type, or be a type that implements a particular interface (or set of interfaces).
Type, on the other hand, is a class that describes information about a type in your application or one of it's libraries. Specific kinds of types don't inherit or extend Type - rather there is a different instance of Type for each type available. You cannot use generic constraints to control which instances of Type may be added to your collection.
Without more detail about how you want to "constrain" the information in the collection, it's hard to say what route you should take. For example, if all you want to do is ensure that only unique types (no dups) are stored, that can be achieved with a HashSet (rather than a list). But if you want something more specialized - like limiting the Type instances that can be added to some subset of types, then you will likely need to implement your own collection, and implement gaurd logic in the Add/Insert methods.
In this particular scenario, where it seems we have a "factory" pattern, we would constrain the method invoking the activator, such as
private readonly List<Type> _supportedTypes = new List<Type> ();
public void RegisterSupportedType<T> () where T : SomeConstraintType
{
_supportedTypes.Add (typeof (T));
}
// if we do not know the type, but somehow know an index to type
public object Create (int supportedTypeIndex)
{
object untyped = Activator.
CreateInstance (_supportedTypes[supportedTypeIndex]);
return untyped;
}
// if we know instance type\subtype (eg interface) and know an index
public T Create<T> (int supportedTypeIndex)
{
T typed = default (T);
object untyped = Create (supportedTypeIndex);
if (!(untyped is T))
{
// throw meaningful exception :)
}
typed = (T)(untyped);
return typed;
}
An alternative, is to create a constrained Type
public class ConstrainedType<T>
{
public Type Type { get; private set; }
public ConstrainedType (Type type)
{
// may have this backward, would have to fact check before
// rolling out to prod ;)
if (!typeof (T).IsAssignableFrom (type))
{
// throw meaningful exception!
}
Type = type;
}
}
List<ConstrainedType<SomeTypeConstraint>> list =
new List<ConstrainedType<SomeTypeConstraint>> ();
// will throw meaningful exception if MyClass is not
// SomeTypeConstraint or a sub class
list.Add (new ConstrainedType (typeof (MyClass)));
SomeTypeConstraint baseType =
(SomeTypeConstraint)(Activator.CreateInstance(list[0].Type));
Jon,
If you are using CodeContracts, you could require a number of known types. The code analysis would flag any calls to your collection with invalid types.
public class TypeCollection : List<Type>
{
public TypeCollection()
{
}
public new void Add(Type type)
{
Contract.Requires(type == typeof(string) || type == typeof(Stream));
base.Add(type);
}
}
public class TestCollection
{
public void Test()
{
TypeCollection collection = new TypeCollection();
// This gets compile time warning:
collection.Add(typeof(int));
}
}
But, if you know the types in advance, it might make more sense to specify them all in an enum and create a collection of valid enums for the type creation you want to support.
first way(seems stupid but it is safe):
(create a wrapper over the List || implement IList) and check .Exists(item) in the .Add Method.
If you were to implement your own collection, you could use generic type constraints:
public class MyList<T>
where T : IMyConstraint

Categories