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.
Related
I want to validate a class, that has a property of a generic type:
class Foo
{
[ValidHistoryDate]
public MyType<string> bar;
[ValidHistoryDate]
public MyType<int> baz;
[ValidHistoryDate]
public MyType<float> bat;
}
class MyType<T>
{
public string date;
public T property;
}
The generic type also contains a date, attribute (string), that should be validated against a valid date, so I wrote this function to do this:
public class ValidHistoryDateAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
return true;
var v = (List<MyType<object>>)value;
bool valid = true;
foreach (var f in v)
{
if (!Regex.Match(f.Date, #"^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$").Success)
valid = false;
}
return valid;
}
}
The validation does not care about the property "property", but it should care about the string.
Unfortunately the cast fails:
var v = (List<MyType<object>>)value;
I mean: Of course it does, because "object" is not the real type. I want to use the validation attribute for all types and in the validation I actually do not even care about "property".
Any way to solve this in a nice way? I do not want to add a ValidHistoryDateAttribute for every possible type.
If I were to do this I would add a non-generic base type into your code:
public class ValidatableObject
{
public string date;
}
And then my class would be:
class MyType<T> : ValidatableObject
{
public T property;
}
Your validation code would then refer to the base class which makes things a lot simpler.
It looks like you are actually trying to cast something of type List<GenerericHistory<T>> which will run into Variance problems. If you are assuming you are using my base class the incoming item cannot easily be converted to List<ValidatableObject> - to see why consider that the actual list should only allow adding of GenerericHistory<T> (where T is a specific type) objects whereas a List<ValidatableObject> would allow adding of GenerericHistory<T> objects of any type. Thus the cast is not allowed.
If you were to change the list to an IEnumerable<GenerericHistory<T>> then you would be able to cast to IEnumerable<ValidatableObject>. The reason is that this time we have a readOnly object so all we are doing is getting out objects of type ValidatableObject and since know that the actual class will only ever return GenerericHistory<T> (for specific T) we also know it always returns of type ValidatableObject and thus this time the cast is allowed.
The last bit is based partly on speculation since your code seems to be inconsistent with regards to the use of List<T> in your code. I assume the validator is correct that a property on your validatable object is a list but obviously I have no idea if that List can be changed, etc.
I'm trying to create a method with generic parameters:
public List<DTListItem> MapDTListResponse(List<App.Order.DT> dtList)
{
return dtList.Select(MapDTListResponse).ToList();
}
public DTListItem MapDTListResponse(App.Order.DT dt)
{
return RecMap<DTListItem, App.Order.DT>(dt);
}
private T RecMap<T,TU>(TU newObject)
{
if (TU is IEnumerable) // this doesn't work; what do i check for here
{
//Also, how do i get this bit to replicate MapDTListReponse
newObject.Select(RecMap).ToList();
}
else
{
return Mapper.Map<T>(newObject);
}
}
As you can see, the first method takes and returns a collection and simply calls the second method (having the same name but different signature) for each element in the collection.
I want to create a generic method which will handle both cases. It should call itself if a collection is passed through. For this I need to check if the type is IEnumerable but the line T is IEnumerable has the following error
TU is a type which is not valid in the given context.
Also, newObject.Select(Map).ToList(); has the following error
TU does not contain a definition for Select
The is operator takes an object instance on its left hand side, so it can't be used like that. Instead, you can do this:
if (newObject is IEnumerable) // ...
And because you want to use the instance as a collection later on, you can use the as operator instead:
var newCollection = newObject as IEnumerable<T>;
if (newCollection != null) // ...
Worth pointing out that in cases where all you have is a type (and not an instance), you can achieve the same thing through the IsAssignableFrom method of the Type class, like this:
public static bool IsSequence<T>() => typeof(IEnumerable).IsAssignableFrom(typeof(T));
I have an inheritance tree like so:
BaseType
TypeA : BaseType
TypeB : BaseType
TypeC : BaseType
Each derived object has a variable named objectName that defines that object's name.
I also have an array and a list that both hold theBaseType objects as well as any objects derived from BaseType. The array has objects stored in it upon being created, meanwhile the list is empty for future use:
BaseType[] arrayA = new BaseType[] { new TypeA(), new TypeB(), new TypeC(), }
List<BaseType> listA = new List<BaseType>;
I also have a method that is used to add an object that is in the array to the list:
public void AddToList(BaseType itemToAdd)
{
if(itemToAdd.objectName == "Type A")
{
listA.Add(new TypeA());
}
else if(itemToAdd.objectName == "Type B")
{
listA.Add(new TypeB());
}
else if(itemToAdd.objectName == "Type C")
{
listA.Add(new TypeA());
}
}
How can I avoid having to use all of those if commands? At one point I tried:
public void AddToList(BaseType itemToAdd)
{
listA.Add( new itemToAdd());
}
Which did not work. So how can I go about doing something like this? The objects are constantly growing and I don't want to have to put an if for every derived object I add. I should also mention, not sure if this will have any bearing on the solution, I've been using folders to organize the .cs files. So I have all of the derived classes in a folder named "Types" so to create a new instance of that object I have to type:
listA.Add(new Types.TypeA());
well, the first thing I see is that you're instantiating your items, and not just passing the item in
are you trying to do the following?
public void AddToList(BaseType itemToAdd)
{
listA.Add(itemToAdd);
}
the reason
public void AddToList(BaseType itemToAdd)
{
listA.Add( new itemToAdd());
}
doesn't work is because itemToAdd is not a type, it's a variable of the type BaseType. you can't use the new keyword on it. it just doesn't make sense.
if you're trying to copy the item, you can do something like the following.
public void AddToList(BaseType itemToAdd)
{
listA.Add(itemToAdd.Copy());
}
You will have to write your own copy method for this part to work.
Why is your AddToList creating new objects instead of adding the itemToAdd? In other words:
public void AddToList(BaseType itemToAdd)
{
listA.Add(itemToAdd);
}
Also, there is no need to have a string for the type of object. You can get the type of any object by using:
myObj.GetType();
And you can compare the type of an object using typeof:
if (myObj.GetType() == typeof(TypeA))
If you really, really must create new objects of the same type as itemToAdd, then you can use Activator.CreateInstance to avoid all those type checks:
listA.Add((BaseType)Activator.CreateInstance(itemToAdd.GetType());
But I suspect that isn't what you want to do anyway.
Well, you could make a factory to class to create the object you want based on the class type passed in and use it like this:
public void AddToList(BaseType itemToAdd)
{
listA.Add(ItemFactory.Create(itemToAdd.objectName));
}
But of course, this just pushes the question down a level (but still improves the readability of the AddToList code).
To do what you're really asking requires, I think, either doing what you have already suggested: if-else chains (or a switch perhaps) to create an instance of the correct type; or using reflection to new up an instance of a dynamically chosen class.
As simple example:
BaseType Create(BaseType source)
{
var constructor = source.GetType().GetConstructor(new Type[0]);
return constructor.Invoke(new object[0]) as BaseType;
}
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
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