I have a bit complicated issue to solve.
I have a list of objects though later the list will be filled with two different type of instances.
First type is MyFirstType<T1, T2> and second type is MySecondType<T>
Now I need to run though the list of objects and ask which one of the two is each item. Then I need to do some custom logic on the item.
For example:
foreach(object obj in list)
{
if(obj is MyFirstType<T1, T2>)
{
// do something
}
else if(obj is MySecondType<...>)
{
}
}
The problem is T or T1 and T2 could be any types so how do I write such an if - Is Keyword statement that only comparies if MyFirstType but not the generics inside? if(obj is MyFirstType<T1, T2>) does not work since it needs concrete types for T1 and T2.
Like mentioned just need comparison without T1 and T2. Any ideas how to solve this?
You can use IsGenericType property of Type class to check if obj.GetType() is generic, and then use GetGenericTypeDefinition to get generic type definition, which can be compared to typeof(MyFirstType<,>) and typeof(MySecondType<>):
foreach(object obj in list)
{
if(obj.GetType().IsGenericType)
{
if(obj.GetType().GetGenericTypeDefinition() == typeof(MyFirstType<,>))
{
// do something
}
else if(obj.GetGenericTypeDefinition() == typeof(MySecondType<>))
{
}
}
}
The cheap solution: create a flag interface which you derive in your types. This is just a helper to determine the type.
Use reflection and check the type definition and check the name of the type.
Why don't you use polymorphism? Have the two types implement an interface with a common method. Then in the implementation of each type write the code for the method you need.
public interface ICommon
{
void DoThis();
}
For MyFirstType and MySecondType you will have:
public class MyFirstType<T> : ICommon
{
public void DoThis()
{
//DoThis
}
}
public class MySecondType<T1,T2> : ICommon
{
public void DoThis()
{
//DoThis
}
}
Then you could write the following foreach loop:
foreach(object obj in list)
{
obj.DoThis();
}
Related
I have a question about loading types with reflection. I am attempting to filter the list of types in an Assembly by those which implement an interface with two generic parameters. I don't intend to explicitly tell which types are those generic parameters since I want all classes that implement the interface but whenever I attempt to use typeof(IExample<>) it gets marked as an error. However, it's possible to do it with an interface that only has one generic parameter.
I would really appreciate some help with this! Thanks in advance :)
public interface IExample<T, E>
{
}
This is how my interface would looks like.
And then I currently have to classes that implement it.
public class C
{
}
public class A : IExample<string, C>
{
}
Public class B : IExample<XMLDocument, C>
{
}
You weren't to far off from what I could examine from your question. In order to get the correct generic type, without any generic arguments you need to call typeof(IExample<,>), note that there is a comma!
For the other part of your question on how to get those types you can do something like the following:
public static IEnumerable<Type> GetTypesWithGenericArguments(Assembly assembly, Type implementingInterface)
{
var types = assembly.GetTypes();
// Loop over all Types in the assembly
foreach (var type in types)
{
// Skipping all Types which aren't classes
if (!type.IsClass)
continue;
var implementedInterfaces = type.GetInterfaces();
// Loop over all interfaces the type implements
foreach (var implementedInterface in implementedInterfaces)
{
// Return the type if it one of its interfaces are matching the implementingInterface
if (implementedInterface.IsGenericType && implementedInterface.GetGenericTypeDefinition() == implementingInterface)
{
yield return type;
// You can leave the loop, since you don't need to check the other
// interfaces, since you already found the one you were searching for.
break;
}
}
}
}
Which could be used like that:
public static void Main(string[] args)
{
foreach (var item in GetTypesWithGenericArguments(Assembly.GetCallingAssembly(), typeof(IExample<,>)))
{
Console.WriteLine(item.Name);
}
// This would print to the Console:
// A
// B
}
I have a method that is overloaded 3 times with the exact same functionality, the only change is one parameter which is a list of a concrete type.
private void _doWork(string name, List<TargetItem> members)
{
foreach(var member in members)
{
_doExtraWork(member.TimeToWork);
}
}
private void _doWork(string name, List<NonTargetItem> members)
{
foreach(var member in members)
{
_doExtraWork(member.TimeToWork);
}
}
Thing to know here is the 2 classes in the lists are coming from a WSDL definition. The operation in the iteration is on shared members as they derive from the same base class, however this inheritance is abstracted in the WSDL.
I have tried to do something like this -
private void _doWork<T>(string name, List<T> members)
{
var commonList = new List<>(); /// what type should I use here?
if(typeof (T) == typeof(TargetItem))
{
commonList = members; // assume equal to means copying members to commonList with type conversion
}
if(typeof (T) == typeof(NonTargetItem))
{
commonList = members;
}
foreach(var member in commonList)
{
_doExtraWork(member.TimeToWork);
}
}
Is this the right way to approach the problem and refactor this common code, or am I missing something here?
you can do something like this
private static void _doWork<T>(string name, T members) where T : IEnumerable
{
foreach(var member in members)
{
_doExtraWork(member.TimeToWork);
}
}
In your Calling Code
_doWork("sdfsd", new List<TargetItem>()); // here just as example I am passing new instance
_doWork("sdfsd", new List<NonTargetItem>()); // here just as example I am passing new instance
As the List<T> is of type IEnumerable<T> which in turn is of type IEnumerable. You can add IEnumerable generic constaints in your generic functions. In this way, you do not have to do type checking in your generic functions.
If you want to implement single doExtraWork method then you need to have CommonType for both TargetItem and NonTargetItem. you can solve this using Adapter Pattern like below
Interface IItem
{
int TimeToWorkAdapt {get;}
}
//Now create a wrapper class for TargetItem and NonTargetItem
Class TargetItemAdapt : TargetItem,IItem
{
public int TimeToWorkAdapt
{
get { base.TimeToWork;}
}
}
Class NonTargetItemAdapt : NonTargetItem,IItem
{
public int TimeToWorkAdapt
{
get { base.TimeToWork;}
}
}
// write a generic function which wrap calls to your do extra work method but with generic constriants to interface
private static void _doExtraWork<T>(T members) where T : IItem
{
_doExtraWork(member.TimeToWorkAdapt);
}
// In your Main program...now use our wrapper classes
_doWork("sdfsd", new List<TargetItemAdapt>()); // here just as example I am passing new instance
_doWork("sdfsd", new List<NonTargetItemAdapt>()); // here just as example I am passing new instance
I chose to downcast from the caller
_doWork("Target", Object.TargetItems.ToList<BaseClass>());
_doWork("NonTarget", Object.NonTargetItems.ToList<BaseClass>());
-- Context
I have the following 5 objects
IChangeStatus<T>
myFirstClass : IChangeStatus<firstClassEnum>
mySecondClass : IChangeStatus<secondClassEnum>
myClassHandler<TEntity>
myFirstClassHandler : myClassHandler<myFirstClass>
for the purposes of the question we can assume the interface only has the property
T Status { get; }
-- Questions
1.- How can I ask in a method in myClassHandler if an instance of TEntity implements IChangeStatus?
2.- How can I iterate over an IEnumerable of TEntity assuming their specific IChangeStatus?
To check if your class implements IChangeStatus, you can simply do:
public void FooMethod(ClassType myClass)
{
var doesImplementIChange = myClass as IChangeStatus<SomeClass>
if (doesImplementIChange != null)
{
// Do stuff..
}
}
To iterate over an IEnumerable of your classes:
foreach (var data in myClass.OfType<MyType>())
{
// Do stuff..
}
or, you could do:
foreach (var cls in myClass)
{
var myCls = myClass as IChangeStatus<SomeClass>;
if (myCls != null)
{
// Do stuff..
}
}
If you want to use T from IChangeStatus<T> in MyClassHandler, you will have to add another type parameter. For example:
class MyClassHandler<TEntity, TStatus>
where TEntity : IChangeStatus<TStatus>
{
public IEnumerable<TStatus> Statuses
{
get { return _entities.Select(entity => entity.Status); }
}
}
The where clause will ensure that the entity and status types are correlated.
If you don't want to do that, you could add an additional non-generic interface that exposes a Status property of the type Object. You'd lose some static typing that way, but you would not need the extra type parameter.
I found this other SO Question - Check if a type implements a generic interface without considering the generic type arguments which gave me a more generic answer which is what I was looking for:
return entity.GetType().GetInterfaces()
.Where(i => i.IsGenericType)
.Any(i => i.GetGenericTypeDefinition() == typeof(IChangeStatus<>));
As to the iteration over the IEnumerable assuming the specific type of IChangeStatus, since we got that to point then the type does implement the interface thus has a Status property... so I went for dynamic type.
I have several templated objects that all implement the same interface:
I.E.
MyObject<datatype1> obj1;
MyObject<datatype2> obj2;
MyObject<datatype3> obj3;
I want to store these objects in a List... I think I would do that like this:
private List<MyObject<object>> _myList;
I then want to create a function that takes 1 parameter, being a datatype, to see if an object using that datatype exists in my list.... sorta clueless how to go about this. In Pseudo code it would be:
public bool Exist(DataType T)
{
return (does _myList contain a MyObject<T>?);
}
Some Clarification....
My interface is IMyObject<T>, my objects are MyObject<T>. I have a new class MyObjectManager which I need to have a List of MyObject<T> stored within. I need a function to check if a MyObject<T> exists in that list. The type T are datatypes which were auto-generated using T4.... POCO classes from my Entity Data Model.
You can make a generic function:
public bool Exists<T>() where T : class {
return _myList.OfType<MyObject<T>>().Any();
}
Note that this requires that you know T at compile-time.
If all you have is a System.Type object at runtime, you'll need to use reflection:
public bool Exists(Type t) {
var objectOfT = typeof(MyObject<>).MakeGenericType(t);
return _myList.Any(o => o.GetType() == objectOfT);
}
Note, however, that a List<MyObject<object>> cannot hold a MyObject<SomeType>.
You need to change the list to a List<object>, or make MyObject implement or inherit a non-generic type and make the list contain that type.
How about an extension method?
public static bool HasAny(this IEnumerable source, Type type) {
foreach (object item in source)
if (item != null && item.GetType().Equals(type))
return true;
return false;
}
Usage:
bool hasDataType1 = myList.HasAny(typeof(MyObject<datatype1>));
Note that if you don't want to have to type out typeof(...) -- i.e., if you basically want your Exist method to only care about objects of type MyObject<T>, I'd go with something like SLaks's answer:
public static bool Exist<T>(this IEnumerable source) {
return source.OfType<MyObject<T>>().Any();
}
Also, SLaks is right that you really can't have a List<MyObject<object>> that's full of anything other than objects of type MyObject<object> or some derived class (and MyObject<datatype1>, etc. do not derive from MyObject<object> -- generics don't work that way).
Another way I might suggest to work around the whole "you can't get the type of a generic class using a System.Type object without using reflection" issue would be this: Make your MyObject<T> implement a non-generic interface, like this:
public interface IMyObject {
Type DataType { get; }
}
public class MyObject<T> : IMyObject<T>, IMyObject {
public Type DataType {
get { return typeof(T); }
}
}
Then your list could be a List<IMyObject> (the non-generic interface) and your Exist method could look like this:
public static bool Exist<T>(this IEnumerable source, Type type) {
return source.OfType<IMyObject>().Any(x => x.DataType.Equals(type));
}
Since they all implement the same interface, instead of casting them to object and calling GetType (which can be expensive) why not add a property to your interface called class name (or something)? Then you can use the linq in order to grab that property. And don't forget using System.Linq
using System.Linq;
public bool Exist(List<IMyInterface> objects, IMyInterface typeToCheck)
{
return objects.Any(t => t.ObjectName == typeToCheck.ObjectName);
}
I've got a base class:
public abstract class StuffBase
{
public abstract void DoSomething();
}
And two derived classes
public class Stuff1 : StuffBase
{
public void DoSomething()
{
Console.WriteLine("Stuff 1 did something cool!");
}
public Stuff1()
{
Console.WriteLine("New stuff 1 reporting for duty!");
}
}
public class Stuff2 : StuffBase
{
public void DoSomething()
{
Console.WriteLine("Stuff 2 did something cool!");
}
public Stuff1()
{
Console.WriteLine("New stuff 2 reporting for duty!");
}
}
Okay, now say I've got a list of items:
var items = new List<StuffBase>();
items.Add(new Stuff1());
items.Add(new Stuff2());
and I want them all to call their DoSomething() method. I could expect to just iterate the list and call their DoSomething() method, so let's say I've got a method to do that called AllDoSomething() that just iterates over the list and does the job:
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
What is the practical difference of the following method?
public static void AllDoSomething<T>(List<T> items) where T: StuffBase
{
items.ForEach(i => i.DoSomething());
}
Both methods appear in real terms, although being syntactically different, to be doing the same thing.
Are they just different ways of doing the same thing? I understand generics and type constraints but can't see why I would use one way over the other in this instance.
This is because as of yet, C# does not support Covariance.
More formally, in C# v2.0 if T is a
subtype of U, then T[] is a subtype of
U[], but G is not a subtype of G
(where G is any generic type). In
type-theory terminology, we describe
this behavior by saying that C# array
types are “covariant” and generic
types are “invariant”.
Reference: http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx
If you have the following method :
public static void AllDoSomething(List<StuffBase> items)
{
items.ForEach(i => i.DoSomething());
}
var items = new List<Stuff2>();
x.AllDoSomething(items); //Does not compile
Where as if you use the generic type constraint, it will.
For more information about Covariance and Contravariance], check out Eric Lippert's series of posts.
Other posts worth reading :
http://www.pabich.eu/blog/archive/2008/02/12/c-generics---parameter-variance-its-constraints-and-how-it.aspx
http://blogs.msdn.com/rmbyers/archive/2006/06/01/613690.aspx
http://msdn.microsoft.com/en-us/library/ms228359(VS.80).aspx
http://www.csharp411.com/convert-between-generic-ienumerablet/
http://research.microsoft.com/apps/pubs/default.aspx?id=64042
Why can't List<parent> = List<child>?
Suppose you had a list:
List<Stuff1> l = // get from somewhere
Now try:
AllDoSomething(l);
With the generic version, it will be allowed. With the non-generic, it won't. That's the essential difference. A list of Stuff1 is not a list of StuffBase. But in the generic case, you don't require it to be exactly a list of StuffBase, so it's more flexible.
You could work around that by first copying your list of Stuff1 into a list of StuffBase, to make it compatible with the non-generic version. But then suppose you had a method:
List<T> TransformList<T>(List<T> input) where T : StuffBase
{
List<T> output = new List<T>();
foreach (T item in input)
{
// examine item and decide whether to discard it,
// make new items, whatever
}
return output;
}
Without generics, you could accept a list of StuffBase, but you would then have to return a list of StuffBase. The caller would have to use casts if they knew that the items were really of a derived type. So generics allow you to preserve the actual type of an argument and channel it through the method to the return type.
In the example you provided there is no difference but try the following:
List<Stuff1> items = new List<Stuff1>();
items.Add(new Stuff1());
AllDoSomething(items);
AllDoSomething<StuffBase>(items);
The first call works well but the second one does not compile because of generic covariance