Resolving generic method parameters in C# - c#

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

Related

Check if a Type derives from a Interface with more than one Generic Argument

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
}

Implementing generic methods from an interface using another interface

I'm attempting to create a common interface which will allow me n methods of interacting with a database. I want my business application to be able to instantiate any of the connection methodologies and be assured the interface is identical.
Here's a simplified version of what I'm trying now.
Database Interface where IElement is another interface which would define a table.
public interface IDatabase
{
void setItem( IElement task ); //this works fine
List<T> listTasks<T>() where T : IElement; // this doesn't
}
IElement interface:
public interface IElement
{
int id { get; set; }
}
Implementation of IElement:
public class TaskElement: IElement
{
public int id { get; set; }
public string name {get; set; }
}
Implementation of IDatabase:
public class SQLiteDb: IDatabase
{
public SqLiteDb( SQLiteConnection conn )
{
database = conn;
}
public void setItem( IElement task )
{
// works fine when passed a new TaskElement() which is an implementation of IElement.
database.Insert( task );
}
//it all goes off the rails here
public List<T> listItems<T>() where T : IElement
{
var returnList = new List<IElement>
foreach (var s in database.Table<TaskElement>())
{ returnList.Add(s); }
return returnList;
}
I've tried a lot of variations on this but each one gives me a new issue. Here, for instance, there are two errors.
1)
The type arguments for method 'SQLiteDb.listTasks<T>()' cannot be inferred from the usage. Try specifying the type arguments explicitly.
2)
Cannot implicitly convert type 'System.Collections.Generic.List<TaskElement>' to 'System.Collections.Generic.List<T>'
I've tried changing the method to use an explicit type but have had issues there. If I use IElement (my generic interface for all elements )I can't return a list of TaskElement objects (my implementation of IElement) as it doesn't match the return type (List<IElement>) and if I change the return type to List<TaskElement> I'm not longer implementing the interface.
It's worth noting that I can easily get this to work if I stop using the interface and generics, but this seems like an ideal situation to use an interface. Maybe I'm trying to hard to cram a lot of stuff into an interface when another application (like direct inheritance) might be better?
Question
How can I implement an interface with a generic return value while limiting the types which can be returned to only implementations of another interface.
Let's look closely at your implementation of listItems:
public List<T> listItems<T>() where T : IElement
{
var returnList = new List<IElement>
foreach (var s in database.Table<TaskElement>())
{ returnList.Add(s); }
return returnList;
}
What you've done here is written a method where the caller is allowed to ask for any type they want in the list as long as that type implements IElement. But the code in your method doesn't give them a list of the type they want, it gives them a list of IElement. So it's violating the contract.
But the real root of your problem is database.Table<TaskElement>(). That can only ever give you instances of TaskElement. You need to make that T, but to do that you need an additional generic constraint:
public List<T> listItems<T>() where T : IElement, new
{
var returnList = new List<T>
foreach (var s in database.Table<T>())
{
returnList.Add(s);
}
return returnList;
}
This is because database.Table<T> has a new constraint, which means that it can only be given types that have a zero-parameter constructor (because that method is going to create instances of the given class).
I belive it should be something like this
public List<T> listItems<T>() where T : IElement
{
var returnList = new List<T>
foreach (var s in database.Table<T>())
{ returnList.Add(s); }
return returnList;
}
I think you are on the right track with explicitly defining your list like this:
public interface IDatabase
{
void setItem( IElement task ); //this works fine
List<IElement> listTasks<IElement>();
}
Since you can't directly cast List <TaskElement> to List <IElement> you will have to do a conversion in your listTasks method. There are several methods recommended here: Shorter syntax for casting from a List<X> to a List<Y>?. I think the Linq method is the simplest if you are ok with using Linq:
List<IElement> listOfIElement = listOfTaskElement.Cast<IElement>().ToList()
You need to use the Generic type when creating the object instance:
Instead of
var returnList = new List<IElement>();
Do this
var returnList = new List<T>();

Infer Generic Type of Interface

-- 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.

Dilemma in calling constructor of generic class

I have this generic singleton that looks like this:
public class Cache<T>
{
private Dictionary<Guid, T> cachedBlocks;
// Constructors and stuff, to mention this is a singleton
public T GetCache(Guid id)
{
if (!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id, LoadFromSharePoint(id))
return cachedBlocks[id];
}
public T LoadFromSharePoint(Guid id)
{
return new T(id) // Here is the problem.
}
}
The error message is:
Cannot create an instance of type T because it does not have the new() constraint.
I have to mention that I must pass that id parameter, and there is no other way to do so. Any ideas on how to solve this would be highly appreciated.
Normally you would constrain the type T to a type that has a default constructor and call that. Then you'd have to add a method or property to be able to provide the value of id to the instance.
public static T LoadFromSharePoint<T>(Guid id)
where T : new() // <-- Constrain to types with a default constructor
{
T value = new T();
value.ID = id;
return value;
}
Alternatively since you specify that you have to provide the id parameter through the constructor, you can invoke a parameterized constructor using reflection. You must be sure the type defines the constructor you want to invoke. You cannot constrain the generic type T to types that have a particular constructor other than the default constructor. (E.g. where T : new(Guid) does not work.)
For example, I know there is a constructor new List<string>(int capacity) on List<T>, which can be invoked like this:
var type = typeof(List<String>);
object list = Activator.CreateInstance(type, /* capacity */ 20);
Of course, you might want to do some casting (to T) afterwards.
To do this you should specify what T is. Your Cache<T> can hold anything? Tiger, Fridge and int as well? That is not a sound design. You should constrain it. You need an instance of T which will take a Guid to construct the instance. That's not a generic T. Its a very specific T. Change your code to:
public class Cache<T> where T : Cacheable, new()
{
private Dictionary<Guid, T> cachedBlocks;
// Constructors and stuff, to mention this is a singleton
public T GetCache(Guid id)
{
if (!cachedBlocks.ContainsKey(id))
cachedBlocks.Add(id, LoadFromSharePoint(id))
return cachedBlocks[id];
//you're first checking for presence, and then adding to it
//which does the same checking again, and then returns the
//value of key again which will have to see for it again.
//Instead if its ok you can directly return
//return cachedBlocks[id] = LoadFromSharePoint(id);
//if your LoadFromSharePoint is not that expensive.
//mind you this is little different from your original
//approach as to what it does.
}
public T LoadFromSharePoint(Guid id)
{
return new T { Key = id }; // Here is no more problem.
}
}
public interface Cacheable
{
Guid Key { get; set; }
}
Now derive all the cacheables (whatever Ts that you will pass it for Cache<T>) from the interface Cacheable.
In order to use the constructor of a Generic Type without any constraint, and within the class, the syntax where T : class, new() needs to be used
This enables to change values of attributes (fields) - not only get/set properties) at runtime depending the target class used
First, declaring the generic class:
public class Foo<T> where T : class, new()
{
public T oneEmptyElement()
{
return new T();
}
public T setAttribute(string attributeName, string attributeValue)
{
T objT = new T();
System.Reflection.FieldInfo fld = typeof(T).GetField(attributeName);
if (fld != null)
{
fld.SetValue(objT, attributeValue);
}
return objT;
}
public List<T> listOfTwoEmptyElements()
{
List<T> aList = new List<T>();
aList.Add(new T());
aList.Add(new T());
return aList;
}
}
Declare then a potential target class:
public class Book
{
public int name;
}
And finally the call can be done like this:
Foo<Book> fooObj = new Foo<Book>();
Book aBook = fooObj.oneEmptyElement();
aBook.name = "Emma";
Book anotherBook = fooObj.setAttribute("name", "John");
List<Book> aListOfBooks = fooObj.listOfTwoEmptyElements();
aListOfBooks[0].name = "Mike";
aListOfBooks[1].name = "Angelina";
Console.WriteLine(aBook.name); //Output Emma
Console.WriteLine(anotherBook.name); //Output John
Console.WriteLine(aListOfBooks[0].name); // Output Mike
Console.WriteLine(aListOfBooks[1].name); // Output Angelina

Getting the constructor of an Interface Type through reflection, is there a better approach than looping through types?

I have written a generic type: IDirectorySource<T> where T : IDirectoryEntry, which I'm using to manage Active Directory entries through my interfaces objects: IGroup, IOrganizationalUnit, IUser.
So that I can write the following:
IDirectorySource<IGroup> groups = new DirectorySource<IGroup>(); // Where IGroup implements `IDirectoryEntry`, of course.`
foreach (IGroup g in groups.ToList()) {
listView1.Items.Add(g.Name).SubItems.Add(g.Description);
}
From the IDirectorySource<T>.ToList() methods, I use reflection to find out the appropriate constructor for the type parameter T. However, since T is given an interface type, it cannot find any constructor at all!
Of course, I have an internal class Group : IGroup which implements the IGroup interface. No matter how hard I have tried, I can't figure out how to get the constructor out of my interface through my implementing class.
[DirectorySchemaAttribute("group")]
public interface IGroup {
}
internal class Group : IGroup {
internal Group(DirectoryEntry entry) {
NativeEntry = entry;
Domain = NativeEntry.Path;
}
// Implementing IGroup interface...
}
Within the ToList() method of my IDirectorySource<T> interface implementation, I look for the constructor of T as follows:
internal class DirectorySource<T> : IDirectorySource<T> {
// Implementing properties...
// Methods implementations...
public IList<T> ToList() {
Type t = typeof(T)
// Let's assume we're always working with the IGroup interface as T here to keep it simple.
// So, my `DirectorySchema` property is already set to "group".
// My `DirectorySearcher` is already instantiated here, as I do it within the DirectorySource<T> constructor.
Searcher.Filter = string.Format("(&(objectClass={0}))", DirectorySchema)
ConstructorInfo ctor = null;
ParameterInfo[] params = null;
// This is where I get stuck for now... Please see the helper method.
GetConstructor(out ctor, out params, new Type() { DirectoryEntry });
SearchResultCollection results = null;
try {
results = Searcher.FindAll();
} catch (DirectoryServicesCOMException ex) {
// Handling exception here...
}
foreach (SearchResult entry in results)
entities.Add(ctor.Invoke(new object() { entry.GetDirectoryEntry() }));
return entities;
}
}
private void GetConstructor(out ConstructorInfo constructor, out ParameterInfo[] parameters, Type paramsTypes) {
Type t = typeof(T);
ConstructorInfo[] ctors = t.GetConstructors(BindingFlags.CreateInstance
| BindingFlags.NonPublic
| BindingFlags.Public
| BindingFlags.InvokeMethod);
bool found = true;
foreach (ContructorInfo c in ctors) {
parameters = c.GetParameters();
if (parameters.GetLength(0) == paramsTypes.GetLength(0)) {
for (int index = 0; index < parameters.GetLength(0); ++index) {
if (!(parameters[index].GetType() is paramsTypes[index].GetType()))
found = false;
}
if (found) {
constructor = c;
return;
}
}
}
// Processing constructor not found message here...
}
My problem is that T will always be an interface, so it never finds a constructor.
Is there a better way than looping through all of my assembly types for implementations of my interface?
I don't care about rewriting a piece of my code, I want to do it right on the first place so that I won't need to come back again and again and again.
EDIT #1
Following Sam's advice, I will for now go with the IName and Name convention. However, is it me or there's some way to improve my code?
Thanks! =)
You have several possibilities here.
Sam gave you one answer.
Use some sort of a container, see Depencency injection.
Constrain the type T to have a default constructor (Constructor constraint) and add a SetEntry(DirectoryEntry) to the IDirectoryEntry interface.
Refactor your code so that your directory source is not burdened with creating new instances. You could maybe have different searchers, each returning correct type.
class DirectorySource<T>: IDirectorySource<T> {
public DirectorySource(ISearcher<T> searcher) {
Searcher = searcher;
}
public IList<T> ToList() {
string filter = "...";
return Searcher.FindAll(filter);
}
}
class GroupSearcher: ISearcher<Group> {
public IList<Group> FindAll(string filter) {
entries = ...
var entities = new List<Group>();
foreach (var entry in entries)
entities.Add(new Group(entry.GetDirectoryEntry());
return entities;
}
}
You would then instantiate you DirectorySource like this:
IDirectorySource<Group> groups = new DirectorySource<Group>(new GroupSearcher());
... :)
EDIT:
You could also use lambda expressions.
class DirectorySource<T>: IDirectorySource<T> {
// Or you could put the parameter in constructor if this is not the only place
// where you create new instances of T
public IList<T> ToList(Func<DirectoryEntry, T> create) {
...
foreach (var entry in entries)
entities.Add(create(entry.GetDirectoryEntry()));
return entities;
}
}
IList<Group> groups = new DirectorySource<Group>().ToList(entry => new Group(entry));
And regarding class responsibilities and such, do you have special handling for each supported type in eg. Change(T) method (or any other)? If so then I would still refactor and use IDirectoryEntryManager<T> (or some other name) which would know how to handle appropriate type. DirectorySource could then use that class to manipulate concrete types and not be burdened with details that do not belong there.
You can loop through all classes in the assembly and find one that implements the interface. You'll need to decide what to do when you find multiple implementations.
Or if you have a consistent naming scheme, you can generate the class name from the interface name.
You can create special attribute to point implementing type without the necessity to rely on naming convention.
[AttributeUsage(AttributeTargets.Interface)]
public class ImplementingTypeAttribute: Attribute
{
public Type ImplementingType { get; set; }
public ImplementingTypeAttribute(Type implementingType)
{
ImplementingType = implementingType;
}
}
But refactoring is great idea :)

Categories