Is it possible to add a generic delegate Action to a List collection?
I need some kind of simple messaging system for a Silverlight application.
UPDATE
The following is what i realy "want"
class SomeClass<T>
{
public T Data { get; set; }
// and more ....
}
class App
{
List<Action<SomeClass<T>>> _actions = new List<Action<SomeClass<T>>>();
void Add<T>( Action<SomeClass<T>> foo )
{
_actions.Add( foo );
}
}
Compiler:
The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)
initial code snipped
class SomeClassBase
{ }
class SomeClass<T> : SomeClassBase
{
public T Data { get; set; }
// and more ....
}
class App
{
List<Action<SomeClassBase>> _actions = new List<Action<SomeClassBase>>();
void Add<T>( Action<SomeClass<T>> foo )
where T : SomeClassBase
{
_actions.Add( foo );
}
}
The compiler complains - for the _actions.Add() line;
Argument 1: cannot convert from 'System.Action<test.SomeClass<T>>' to 'System.Action<test.SomeClassBase>'
The best overloaded method match for 'System.Collections.Generic.List<System.Action<test.SomeClassBase>>.Add(System.Action<test.SomeClassBase>)' has some invalid arguments
From the application side there is no need for the SomeClassBase class, yet it seems impossible to define a List of Action<SomeClass<T>> elements and the approach with the base-class works when using the class in the List, instead of the Action
Thanks,
jochen
EDIT: Okay, now I see what you're trying to do. I've left the old answer below for posterity :)
Unfortunately you can't express the relationship you want in C# generics, but as you can make sure you're the only one manipulating the collection, you can keep it safe yourself:
Try this:
class App
{
private readonly Dictionary<Type, object> delegateMap;
void Add<T>(Action<SomeClass<T>> foo)
{
object tmp;
if (!delegateMap.TryGetValue(typeof(T), out tmp))
{
tmp = new List<Action<SomeClass<T>>>();
delegateMap[typeof(t)] = tmp;
}
List<Action<SomeClass<T>> list = (List<Action<SomeClass<T>>) tmp;
list.Add(foo);
}
void InvokeActions<T>(SomeClass<T> item)
{
object tmp;
if (delegateMap.TryGetValue(typeof(T), out tmp))
{
List<Action<SomeClass<T>> list = (List<Action<SomeClass<T>>) tmp;
foreach (var action in list)
{
action(item);
}
}
}
}
Note that you could use the fact that delegates are multicast to just keep a Dictionary<Type, Delegate> and combine them together, but I'll leave that as an exercise for the reader :)
Old answer
It's failing for a good reason. Let's get rid of the generics (as they're irrelevant here) and think about a simpler case - fruit and bananas.
You're trying to add an Action<Banana> to a List<Action<Fruit>>. You can't do that - even with the generic variance of C# 4. Why? Because it's not safe. Consider this:
Action<Banana> peeler = banana => banana.Peel();
List<Action<Fruit>> fruitActions = new List<Action<Fruit>>();
fruitActions.Add(peeler); // Nope!
fruitActions[0].Invoke(new Strawberry());
Eek! Now we've got a banana peeler trying to peel a strawberry... what a mess!
Not that the other way round would be acceptable in C# 4:
Action<Fruit> eater = fruit => fruit.Eat();
List<Action<Banana>> bananaActions = new List<Action<Banana>>();
fruitActions.Add(eater); // Yes!
fruitActions[0].Invoke(new Banana());
Here we're adding an Action<Fruit> to a List<Action<Banana>> - that's acceptable, because anything you can do to an Action<Banana> is also valid for an Action<Fruit>.
Will this do what you want?
void Add<T>(Action<SomeClass<T>> foo)
where T : SomeClassBase
{
_actions.Add(x => foo((SomeClass<T>) x));
}
using System;
using System.Collections.Generic;
public delegate void MyDelegate<T>( T i );
public class DelegateList<T>
{
public void Add( MyDelegate<T> del ) {
imp.Add( del );
}
public void CallDelegates( T k ) {
foreach( MyDelegate<T> del in imp ) {
del( k );
}
}
private List<MyDelegate<T> > imp = new List<MyDelegate<T> >();
}
public class MainClass
{
static void Main() {
DelegateList<int> delegates = new DelegateList<int>();
delegates.Add( PrintInt );
delegates.CallDelegates( 42 );
}
static void PrintInt( int i ) {
Console.WriteLine( i );
}
}
Not sure if this is what you want. But try to change you Add method to:
void Add( Action<SomeClassBase> foo )
{
_actions.Add( foo );
}
Update
This will allow you to do something like this:
App app = new App();
Action<SomeClass<int>> action = null; // Initilize it...
app.Add((Action<SomeClassBase>)action);
If you look at the line
List<Action<SomeClass<T>>> _actions = new List<Action<SomeClass<T>>>();
The class T that you are referring to hasn't been declared anywhere. In SomeClass you have the right declaration for a generic class but in your App class you haven't told it what T is in this particular instance.
In summary I don't think this is doing what you want it to. With generics its easiest to imagine that when the code has been compiled there is no such thing as generics[0]. That during the compilation its just making all the classes you are using generically. This means there isn't really a concept of a list of generic classes since by the time you are using them the classes are of a given type and so can't be mixed.
I think the way it would need to work is using more definite class definitions but as Jon Skeet explained that doesn't really work either.
Perhaps the best idea is to take a few step backs and ask a question about what you are doing with this messaging system?
[0] Generics work differently in different languages but this is a good rough principle to work on I think...
I don't know if this is what you want exactly but if you want to have a method which invoke an action for each element in a list you can use an extension method like that :
public static class Extensions
{
public static void Action<T>(this IEnumerable<T> list, Action<T> action)
{
foreach (T element in list)
{
action.Invoke(element);
}
}
}
An exemple of call with myList of type IEnumerable<string>:
myList.Action(element => Console.WriteLine(element));
Maybe LINQ already implements an action in a List but if it's the case I don't know the syntax.
Related
The following test passes, but I'm wondering if a unified treatment is possible. Can it be done?
public abstract class MyInvokable<TResult> {
public abstract TResult Invoke();
}
public class IntInvokable: MyInvokable<int> {
public override int Invoke() {
return 12;
}
}
[Test()]
public void FunctionInvokeTest () {
Func<int> foo = () => 6;
IntInvokable bar = new IntInvokable();
int six = foo.Invoke();
int twelve = bar.Invoke();
Assert.AreEqual(6, six);
Assert.AreEqual(12, twelve);
/* Now, what I really want to do but can't, as far as I can tell:
List<SomeType> list = new List<SomeType>(){foo, bar};
Assert.AreEqual(6, list[0].Invoke());
Assert.AreEqual(12, list[1].Invoke()); */
}
EDIT: started a feature request with Microsoft here:
http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/10185579-create-an-iinvokable-t-interface
C# does not allow anything even remotely close to this type of dynamic behaviour.
But, it you do need to go this route, you can always use dynamic, basically signaling the compiler that all bets are off. This would work:
List<dynamic> list = new List<dynamic>(){foo, bar};
Assert.AreEqual(6, list[0].Invoke());
Assert.AreEqual(12, list[1].Invoke());
but you cannot guarantee in any way that whatever is in the list variable, actually has an Invoke method.
The feature most like this one is TypeScript's structural interfaces - as long as a type has all the methods / properties required by the interface, it's considered to implement the interface.
In C#, the only way that two different things can be considered as having a similar type, is for them to explicitly declare that they implement the same interface, or inherit the same base class.
It would be nice to be able to somehow have a structural semantics in C#, but it's not even on the roadmap, AFAIK.
To have a List<T> where the only requirement you want is that T has a parameterless Invoke method you need to bake that requirement into either an interface or a base class.
So either of these two would work:
public interface IInvokable
{
int Invoke();
}
var l = new List<IInvokable>();
or this:
public class Invokable
{
public virtual int Invoke() { ... }
}
var l = new List<Invokable>();
Obviously, now you need to wrap the delegate in that class, for instance like this:
public class FuncInvokable : IInvokable
{
private readonly Func<int> _Func;
public FuncInvokable(Func<int> func) { _Func = func; }
public int Invoke() { return _Func(); }
}
or... you could just place delegates into the list and wrap all objects in delegates instead:
var l = new List<Func<int>>();
l.Add(foo);
l.Add(() => bar.Invoke());
but there is no way to define this:
var l = new List<Type that has an Invoke method>();
I have an Address class:
public class Address
{
//Some stuff
}
and there's a corresponding *Wrapper class to enforce certain rules on how to
use the Address class:
public class AddressWrapper : IWrapped<Address>
{
private Address _wrapped;
public Address GetWrapped()
{
return _wrapped;
}
//And some more
}
where IWrapped is defined as:
public interface IWrapped<T>
{
T GetWrapped();
}
I have the following generic class for saving these entities (there are other
entities that follow this pattern of Entity and EntityWrapper):
public class GenericRepository
{
private GenericRepository() { }
public static void Add<T>(IWrapped<T> entity)
{
//Do something
}
public static void AddList<T>(IList<IWrapped<T>> entities)
{
//Do something
}
}
and I have this test code:
[Test]
public void UseGenericRepository()
{
AddressWrapper addrW = new AddressWrapper();
addrW.AddrLine1 = "x";
addrW.AddrLine2 = "y";
addrW.AddrLine3 = "z";
addrW.City = "Starling City";
//This works as expected
GenericRepository.Add<Address>(addrW);
IList<AddressWrapper> addrList = new List<AddressWrapper>();
//Fill up the addrList
//This gives error: best overloaded method match has some invalid
//arguments
GenericRepository.AddList<Address>(addrList);
}
AddressWrapped is of type IWrapped<Address> (i.e., it implements it) and
Address is the type parameter being given to the AddList method, so the
types should line up. I know that this is due to my limited knowledge of C#
generics (familiar with Java generics), but can't figure out what's wrong here
--- it should work.
This probably doesn't make any difference, but here's my config:
NHibernate 4.x
.NET Framework (4.5)
This is because of the missing type variance of IList<T>. (IList<int> is not an IList<object>).
Use IEnumerable<T>, because it is covariant:
public static void AddList<T>(IEnumerable<IWrapped<T>> entities)
{
//Do something
}
Reason: If you get an instance of List<AddressWrapper>, the compiler doesn't know if it is compatible with any possible implementation of IList<IWrapped<T>>. Assume another class that implements IWrapped<T>. It wouldn't be compatible when writing to the List. Even though you don't write to the list in AddList, the compiler only accepts compatible types. IEnumerable<T> cannot be written, so it can be variant.
Not related to the question I suggest to use covariance for your own interface as well:
public interface IWrapped<out T>
to make IWrapped<Thing> compatible with IWrapped<SpecificThing>.
MSDN: https://msdn.microsoft.com/en-us/library/ee207183.aspx
To make this clear by an example. Would would you expect happen if we had two types implement IWrapped<T>?
public class AddressWrapper : IWrapped<Address>
{
private Address _wrapped;
public Address GetWrapped()
{
return _wrapped;
}
//And some more
}
public class OtherWrapper : IWrapped<MailBox>
{
public MailBox GetWrapped()
{
throw new MailBox();
}
}
And we tried to add them to a third list inside AddList<T>:
public static void AddList<T>(IList<IWrapped<T>> entities)
{
internalList = new List<IWrapped<T>>();
list.AddRange(entities); // BOOM.
}
The type system is keeping you from making a mistake. List<T> isn't covariant exactly for that reason.
At the point at which you're trying to call AddList(), for all the compiler knows, that method may add objects of any type that implements IWrapper<Address> (i.e. types that aren't AddressWrapper) to the passed in list.
That would be bad because the list you're trying to pass to the method doesn't want to contain anything other than AddressWrappers.
NB: Please see the answer by #StefanSteinegger, it is especially enlightening.
What worked for me was changing the way I was defining addrList, from:
IList<AddressWrapper> addrList = new List<AddressWrapper>();
to:
IList<IWrapped<Address>> addrList = new List<IWrapped<Address>>();
However, I am also changing the signature of the GenericRepository.AddList<T>(..) method to take an IEnumerable as that also helps indicate that the input is read-only. So:
public static void AddList<T>(IEnumerable<IWrapped<T>> entities)
{
//Do some stuff
}
I have just familiarized myself a little bit with C# delegates. One can subscribe multiple delegate instances to a delegate by the "+=" operator. But is it also possible to have a controller class that has delegates for all the methods in second class, and have the methods being added automatically, i.e. without having to add (or even know) each method individually to the corrsponding delegate ?
In simplified code (omitting access modifiers etc.):
class Car
{
void Start();
void Drive();
}
// I would like to have the following class generated automatically
// without needing to repeat all the methods of Car, i.e.
// without declaring a delegate instance for each of them
class CarController
{
delegate void DoSomething();
DoSomething StartAll;
DoSomething DriveAll;
void Subscribe(Car anotherCar)
{
StartAll += anotherCar.Start;
DriveAll += anotherCar.Drive;
}
}
EDIT:
Rawling's solution is the one that I like best. It's simple and clear. As a little tweak I have tried how the thing would work with dynamically typed objects, and it works indeed: complete decoupling between Controller and controlled objects. Of course such usage of "dynamic" is not of everyone's taste...
public class CallAller2 : HashSet<dynamic>
{
public void CallAll(Action<dynamic> action)
{
foreach (dynamic t in this)
{
try {action(t);} catch (RuntimeBinderException) {};
}
}
}
class Bike
{
void Drive();
}
CallAller2 ca = new CallAller2();
ca.Add(new Car());
ca.Add(new Bike());
ca.CallAll(c => c.Start()); // is ignored by Bike which does not implement it
ca.CallAll(c => c.Drive());
Now I realise this is just essentially recreating the much-maligned List<T>.ForEach. Why not just use that, since it's there?
Although it doesn't give you the ability to just call .StartAll or .DriveAll, you could do something as simple as
class CallAller<T> : HashSet<T>
{
public void CallAll(Action<T> action)
{
foreach (T t in this)
{
action(t);
}
}
}
var ca = new CallAller<Car>();
ca.Add(myFirstCar);
ca.Add(mySecondCar);
// Call a simple function
ca.CallAll(c => c.Start());
// Call a function taking parameters
ca.CallAll(c => c.SetRadio(88.1, RadioType.FM));
// Get return values... if you really need to.
Dictionary<Car, int> returnValues = new Dictionary<Car, int>();
ca.CallAll(c => returnValues.Add(c, c.GetNumberOfTyres()));
If you want something with actual methods to call and Intellisense, you'll need to look into code generation - it's possible, but I doubt it'd be worth the hassle.
I think this should work:
//Edit: Don't simplify the MethodInfo mi1 = mi, otherwise you get a problem called Access to modified closure
static IList<Action> getDelegatesFromObject(Object obj)
{
Type type = obj.GetType();
List<Action> Actions = new List<Action>();
foreach (MethodInfo mi in type.GetMethods())
{
MethodInfo mi1 = mi;
Actions.Add(
() => mi1.Invoke(obj, new object[] {})
);
}
return Actions;
}
I have a set of elements which I want to perform operations on. The classic "Visitor" pattern isn't applicable to my situation because:-
My element types are not stable.
I want to Visit based on interface implementation, and some of my elements implement multiple interfaces that require visitation by different visitors - this results in an ambiguous call in those types' Accept methods.
Most of my visitors don't care about most of my elements. Even if I could use the classic Visitor pattern, the overwhelming majority of my Visit methods would be no-ops.
I would like a variant of the Visitor pattern which looks like:-
class Visitor
{
// called when I'm Accepted by a ThingICareAbout
void Visit(ElementICareAbout e)
{
// Do whatever needs done.
}
// called when I'm Accepted by anything else
void Visit(Element e)
{
// Do nothing.
}
}
I came up with the following:-
Related question: c# generic method overload not consistent with abstract Visitor pattern
public interface IAcceptsVisitor
{
void Accept<T>( IVisitor<T> v );
}
public interface IVisitor<T>
{
void Visit( T e );
void Visit<X>( X e );
}
public class Element : IAcceptsVisitor
{
public bool Visited { get; set; }
public Element ()
{
Visited = false;
}
public void Accept<U>( IVisitor<U> v )
{
v.Visit( this );
}
}
public class Visitor : IVisitor<Element>
{
public void Visit( Element e )
{
e.Visited = true;
}
public void Visit<X>( X e )
{
// Do nothing
}
}
but that doesn't work because the compiler can only prefer the non-generic Visit method to the generic one if it knows statically at compile-time that it'll work.
Is there a way to make the above work?
Is there another way entirely?
With respect to 2) I've seen Dynamic Dispatching touted as an "advanced" alternative to the Visitor pattern, but is this really "better" than just going:-
foreach (ThingICareAbout in things.OfType<ThingICareAbout>())
Also worthy of note: I'm using .NET 4, so if the dynamic type helps, I'm willing to give it a shot.
Edit: I've provided my own answer based on the dynamic keyword. However, I'm still extremely interested in hearing about other approaches.
With regards to the Dynamic keyword, this is what I have so far:-
public class ThingIDontCareAbout: IAcceptsVisitor
{
}
public class ThingICareAbout: IAcceptsVisitor
{
public bool Visited { get; set; }
public AdvancedElement()
{
Visited = false;
}
}
public class Visitor
{
public void Visit( IAcceptsVisitor e )
{
dynamic d = e;
this.DynamicVisit( d );
}
private void DynamicVisit( IAcceptsVisitor e )
{
// Do nothing.
}
private void DynamicVisit( ThingICareAbout e )
{
e.Visited = true;
}
}
and you call it with:-
Visitor v = new Visitor();
foreach (IAcceptsVisitor e in things) { v.Visit(e); }
Going to profile this vs type checking. I'm particularly interested in hearing your comments comparing this to:-
foreach (ThingICareAbout e in things.OfType<ThingICareAbout>()) { ...
I like that the dynamic-ness is contained inside the Visitor - and particularly I like that I don't even have to pollute the element types with an Accept method. In particular this means that we can use it to visit types that aren't under our control (typically Expressions or Controls).
I would be certain that this question addresses something that would have been brought up in a previous question, but I was unable to find it.
There is a method in a C# class that takes as a parameter a generic List of a Base Class. I need to pass a list of an inherited class and do not know exactly how to do this. I am getting an error in my attempts. Below is sample code to illustrated this:
public class A
{
public static void MethodC(List<A>)
{
// Do Something here with the list
}
}
public Class B : A
{
// B inherits from A, A is the Base Class
}
// Code utilizing the above method
List<B> listOfB = new List<B>();
A.MethodC( (List<A>) listOfB ); // Error: this does not work
A.MethodC( listOfB.ToList<typeof(A)>() ); // Error: this does not work
A.MethodC( listOfB.ConvertAll<A>(typeof(A)) ); // Error: this does not work
// how can I accomplish this? It should be possible I would think
Note: Here is my final working Method as a reference. I got an even better solution to my problem, but technically it wasn't an answer to the question, since my question was phrased impropertly.
public static DataTable
ObjectCollectionToDataTable<GLIST>
(List<GLIST> ObjectCollection) where GLIST
: BaseBusinessObject
{
DataTable ret = null;
if (ObjectCollection != null)
{
foreach ( var b in ObjectCollection)
{
DataTable dt = b.ToDataTable();
if (ret == null)
ret = dt.Clone();
if (dt.Rows.Count > 0)
ret.Rows.Add(dt.Rows[0].ItemArray);
}
}
return ret;
}
If you have linq available you can do
var ListOfA = ListOfB.Cast<A>().ToList();
You cannot do that. To understand why it is not allowed, imagine what would happen if Add was called on a List<Derived> after it had been cast to a List<Base>.
Also, the answers implying that C# 4.0 will be different are wrong. List will never be modified to allow you to do this. Only IEnumerable will - because it does not allow items to be added to the collection.
Update: The reason it works in the solution you've gone for is because you're no longer passing the same list. You're creating a whole new list which is a copy of the original. This is why I asked about modifying the list; if MethodC makes changes to the number of items on the list, those changes would be made to a copy, not the original list.
I think the ideal solution for you is as follows:
public abstract class A
{
public void MethodC<TItem>(List<TItem> list) where TItem : A
{
foreach (var item in list)
item.CanBeCalled();
}
public abstract void CanBeCalled();
}
public class B : A
{
public override void CanBeCalled()
{
Console.WriteLine("Calling into B");
}
}
class Program
{
static void Main(string[] args)
{
List<B> listOfB = new List<B>();
A a = new B();
a.MethodC(listOfB);
}
}
Notice how, with this solution, you can pass a List<B> directly to MethodC without needing to do that weird conversion on it first. So no unnecessary copying.
The reason this works is because we've told MethodC to accept a list of anything that is derived from A, instead of insisting that it must be a list of A.
You are addressing the lack of covariance in the current C# version. Here is one way of doing it:
listOfB.Cast<A>();
Here is an answer that will exclude any objects in your list of the wrong type. This is a much safer way in my opinion:
List<A> ListOfA = ListOfB.OfType<A>().ToList();
The OfType method will exclude items of the wrong derived class where as the Cast will throw an error.