It may not be possible, but I am hoping it is!
I have a method which has scope of a generic type, and instansiates a List<Func<GenericType>>. I then have another method which recieves a List<Func<T>>. I can't have any knowledge of T in this method.
Example Code
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
RecieveFuncs(funcs);
}
public void RecieveFuncs(List<Func<object>> funcs)
{
//Do some stuff with funcs
}
I was wishing that it would be as easy as using object in place of T and it would be as easy of that. Of course, T isn't an object, it's a Type and therefore I can't interchange them. Any suggestions or is this impossible?
You can make your method generic:
public void RecieveFuncs<T>(List<Func<T>> funcs)
{
//Do some stuff with funcs
}
To call it, you can either declare T explicitly
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
RecieveFuncs<Item>(funcs);
}
or let the type inference magic do its work and keep the call as it is:
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
RecieveFuncs(funcs); // C# automatically infers T = Item
}
If you can't make RecieveFuncs generic for some reason, you could use:
public void PassFuncs<TItem>()
where TItem:class
{
List<Func<TItem>> funcs = new List<Func<TItem>>();
RecieveFuncs(funcs);
}
public void RecieveFuncs(IEnumerable<Func<object>> funcs)
{
//Do some stuff with funcs
}
This requires a generic constraint to reference types for TItem, and needs a co-variant interface like IEnumerable<T> instead of List<T> on the receiving side. If you really want to receive a List<Func<object>> you can create a new list with List<Func<object>>(funcs).
If you know that Item is a reference type, you can use variance of each function (but not of the list):
public void PassFuncs<Item>() where Item : class
{
List<Func<Item>> funcs = new List<Func<Item>>();
var tmp = funcs.ConvertAll(func => (Func<object>)func);
RecieveFuncs(tmp);
}
This creates a new list, but uses the original functions. If that is not possible, you'll need to add an intermediate function:
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
var tmp = funcs.ConvertAll<Func<object>>(func => () => func());
RecieveFuncs(tmp);
}
You could "cast" the Func<Item> to Func<object>, like this
public delegate object Func();
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
RecieveFuncs(funcs.Select<Func<Item>, Func<object>>(f => () => (object)f())
.ToList());
}
public void RecieveFuncs(List<Func<object>> funcs)
{
//Do some stuff with funcs
}
This will work both for reference and value types, although it will box for the value types. If you use only reference types, use #CodesInChaos answer.
Related
This is what I am trying to get
(IList<Foo>)listPropertyInfo.GetValue(item)
This is how I get Foo type
listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]
This is what I tried but couldn't make it successfully
Convert.ChangeType(listPropertyInfo.GetValue(item), IList<listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]>)
and also this;
((typeof(IList<>).MakeGenericType(listPropertyInfo.GetValue(item).GetType().GenericTypeArguments.Single())))(listPropertyInfo.GetValue(item))
this is method where I am trying to implement
public static void trigger(IList<T> result)
{
foreach (var item in result)
{
foreach (var listPropertyInfo in typeof(T).GetProperties().ToList().FindAll(x => x.PropertyType.Name == typeof(IList<>).Name))
{
trigger((IList<Foo>)listPropertyInfo.GetValue(item));
}
}
}
I solved like this;
IList targetList = (IList)listPropertyInfo.GetValue(item);
Type foo = targetList.GetType().GenericTypeArguments.Single();
Type unboundGenericType = typeof(READ<>);
Type boundGenericType = unboundGenericType.MakeGenericType(foo);
MethodInfo doSomethingMethod = boundGenericType.GetMethod("trigger");
object instance = Activator.CreateInstance(boundGenericType);
doSomethingMethod.Invoke(instance, new object[] { targetList, f, properties });
If you use IList notation, Foo must be defined at compile time, you can't use expression that evaluates at runtime for Foo.
After reading your comments and and the code i would argue you are trying to do it at the wrong spot.
Here an example of how you could do this
public class MyGeneric<T>
{
public static void trigger(IList<T> result)
{
// do generic stuff where
// you do not need to know T
}
}
// this class does only explicit Foo related stuff
public class MyNONEGeneric
{
public static void trigger(IList<Foo> list)
{
// do some
}
}
class Program
{
static void Main(string[] args)
{
PersistentGenericBag<Foo> magicBag = myMagic<Foo>();
// call your generic which do some general list related stuff
MyGeneric<Foo>.trigger(list);
// call your none generic which do some foo related stuff
MyNONEGeneric.trigger(list);
}
}
like you can see i did some sort of "separation of concerns" / "single responsibility principle" here.
Every thing does only "one" thing. so if you are in need to change something you will know exactly where.
Also if you are working in a Team you can tell Person A to do the MyGeneric<T> and Person B to do the MyNONEGeneric
Action construct is generic but can that support generic type inside it?
The code snippet shown below is what I'm trying to achieve.
I'm aware of that there are other ways to do it but I am curious whether it can be achieved within an Action construct.
void SomeMethod()
{
Action<int> Initialize = //<T> and where T is all that stuff
(index) =>
{
T obj = new T();
obj.Initialize(index);
obj.DoWork();
};
Initialize<TypeA>(1);
Initialize<TypeB>(2);
}
No, basically - or at least, not within a single instance of an Action - a single instance is inherently closed in terms of generics. Obviously you could use a regular generic method Initialize<T>. If you need a single Action, then it might need to take the type as a parameter:
Action<Type, int> init = (type, index) => {
ISomeInterface obj = (ISomeInterface)Activator.CreateInstance(type);
obj.Initialize();
obj.DoWork();
};
init(typeof(TypeA), 1);
init(typeof(TypeB), 2);
Otherwise:
void Initialize<T>(int index) where T : new(), ISomeInterface {
T obj = new T();
obj.Initialize();
obj.DoWork();
}
void SomeMethod() {
Initialize<TypeA>(1);
Initialize<TypeB>(2);
}
You can create Action<int> delegates to represent separately Initialize<TypeA>(int) and Initialize<TypeB>(int), but not both at the same time, and not the open Initialize<T>(int).
Solution to call non-generic method and pass generic arguments with different generic types?
My imaginary dream:
void FooBulous(Foo<object>[] fooArray) { } // Accept any 'Foo<BaseType>'
var fooArray = new Foo<object>[] // Array of 'Foo<BaseType>'
{
new Foo<Cat>(),
new Foo<Dog>(),
};
FooBulous(fooArray); // Pass the 'Foo<BaseType>[]' array
My reality:
void BarBaric(object[] barArray) { } // Can't constrain to 'Foo<>'
var barArray = new object[] // Same problem
{
new Bar<Cat>(),
new Bar<Dog>(),
};
BarBaric(barArray); // Barbaric! I thought the 'void *ptr' days were over!
In summary:
void Fee(object[] params) { /* WORKS! But not constrained to 'Foo<Base>' */ }
void Fie(Foo<Cat>[] params) { /* Does not accept 'Foo<Dog>' */ }
void Foe(Foo<>[] params) { /* ERROR: 'Type expected' */ }
void Fum(Foo<object>[] params) { /* Cannot convert 'Foo<Cat>' to 'Foo<object>' */ }
Clearly, this can't be done... Is there a clean alternative?
The problem is that a Foo<Cat> isn't a Foo<object>. Suppose Foo looked like this:
public class Foo<T>
{
public void Method(T input)
{
...
}
}
Then a Foo<Cat> would always expect a Cat value for the input parameter to Method. But if you could treat Foo<Cat> as a Foo<object> you could do:
Foo<Cat> catFoo = new Foo<Cat>();
Foo<object> objectFoo = catFoo;
objectFoo.Method(new object()); // Eek! Type safety is broken!
Now generic variance is available in .NET 4 (and C# 4) but only for interfaces and delegates, and only for those decorated appropriate with out and in at the point of the type parameter declaration. That may or may not be useful to you.
Another option is to make Foo<T> derive from an abstract non-generic base class Foo which provides all the members which have nothing to do with T. Then you could write:
void Foobulous(Foo[] fooArray)
...
Foobulous(new Foo[] {
new Foo<object>(),
new Foo<Cat>(),
new Foo<Dog>()
});
and all would be well, so long as Foobulous didn't need to use any of the methods which relied on T - which it shouldn't, given that it can take Foo values with different type parameters anyway.
Is it possible to create a generically typed Action at run time based on some specified types? In this particular scenario, the body of the Action will ultimately ignore the argument types, as the typed Action<> will just be a wrapper around a no-argument Action, e.g.
Action original = () => { };
...
Action<TType> wrapper = (arg) => {
original();
}
Or, even:
Action<TTypeA, TTypeB> wrapper = (arg) => {
original();
}
As you can see, the body of the typed Action<> ignores the arguments, and their type, it's just acting as a wrapper.
If you're curious as to why I want create this wrapper in the first place, the 'basic' version is that I am ultimately converting the Action to a Delegate for doing a Delegate.Combine(), which requires identical types. All I am trying to accomplish with the Delegate.Combine() is a basic notification that the delegate was fired.
At this point I will probably re-work my design to avoid these types of shenanigans, but I am still very curious how this might be accomplished.
The closest I could get was the following:
private static TType GetTypedDelegate<TType>(Action onComplete)
where TType : class
{
MethodInfo info = typeof(TType).GetMethod("Invoke");
ParameterInfo[] parameters = info.GetParameters();
object result;
if (parameters.Length == 0)
result = onComplete;
else if (parameters.Length == 1)
result = GetTypedDelegate<TType>(onComplete, parameters[0].ParameterType);
// etc
TType onCompleteCasted = Delegate.CreateDelegate(typeof(TType), result, "Invoke") as TType;
return onCompleteCasted;
}
private static Delegate GetTypedDelegate<TType>(Action onComplete, Type type)
{
// This line isn't useful for me right now, since I can't just create a new
// instance of the action with a parameterless constructor ... but I thought I'd throw it in here in case it was of use
Type actionType = typeof(Action<>).MakeGenericType(new[] { type });
// Do some magic here with the type information
// The following of course does not work,but you get the idea of what I am aiming for
Action<type> wrapper = (arg1) =>
{
onComplete();
};
return wrapper as Delegate;
}
I think that the easiest option is to write a generic method and then invoke it dynamically (using Reflection or possibly even using C# 4 dynamic):
class Helper {
public static Action<TType> Wrap1<TType>(Action arg) {
return (arg) => { original(); }
}
}
Invoking the method using Reflection and using typ1 as the generic type argument could look like this:
var meth = typeof(Helper).GetMethod("Wrap1");
var gmeth = meth.MakeGenericMethod(new[] { typ1 });
var genericAction = gmeth.Invoke(null, new object[] { action });
If you don't want to use reflection you can setup some classes like this.
public class ActionWrapper<TTypeA>
{
protected readonly Action _original;
public ActionWrapper(Action original)
{
_original = original;
}
public Action<TTypeA> Wrapped { get { return WrappedAction; } }
private void WrappedAction(TTypeA a)
{
_original();
}
}
public class ActionWrapper<TTypeA,TTypeB>:ActionWrapper<TTypeA>
{
public ActionWrapper(Action original) : base(original)
{
}
public new Action<TTypeA, TTypeB> Wrapped { get { return WrappedAction; } }
private void WrappedAction(TTypeA a,TTypeB b)
{
_original();
}
}
I find myself (too) often using a construct like the following:
class MyClass
{
public TypeA ObjectA;
public TypeB ObjectB;
public TypeC ObjectC;
public List<TypeD> ListOfObjectD = new List<TypeD>();
public void DoSmth()
{
return SomeConstruct(
/*...*/
new Setter<TypeA>(a => ObjectA = a), // these are the
new Setter<TypeB>(b => ObjectB = b), // things I'm trying
new Setter<TypeC>(c => ObjectC = c), // to make shorter
new Setter<TypeD>(d => ListOfObjectD.Add(d)),
/*...*/
);
}
}
class Setter<T>
{
public Action<T> Action;
public Setter(Action<T> action)
{
Action = action;
}
}
Is there any way for the Setter class to infer the type of the Action and create the standard (T obj) => Member = obj Action by only passing the Member in some way? I'm thinking of something like:
new Setter(ObjectA)
which of course is not valid syntax, but should give you an idea what I'm trying to achieve. I'm using this construct literally hundreds of time in my code, so the code
saved by this small change would be tremendous.
Edit: Added the TypeD example. The part
new Setter<TypeD>(d => ListOfObjectD.Add(d))
can be simplified to
new Setter<TypeD>(ListOfObjectD.Add)
which is awesome because it cuts from the redundant code. If only <TypeD> could also be inferred it would be perfect. I'm looking for something like this for the others.
#Lazarus - basically the purpose is to return setters, so other objects can set certain members of the class (or it can do other stuff defined in the Action) without accessing the class itself, only the Setter object. The full list of reasons is long and convoluted, but the structuring of the program works like a charm and I doubt needs changing (the example of course is simplified and doesn't really make sense as is).
Edit 2: I found a good way to simplify things for List's:
static class SetterHelper
{
public static Setter<T> GetSetter<T>(this List<T> list)
{
return new Setter<T>(list.Add);
}
}
Now I can just use this:
ListOfObjectD.GetSetter()
which works perfectly! why can't I do the same for T directly? I tried this:
static class SetterHelper
{
public static Setter<T> GetSetter<T>(this T item)
{
return new Setter<T>(t => item = t); // THIS DOESN'T SET THE PASSED MEMBER
}
}
Of course it won't work as intended because it will set item, but not the passed member. I tried adding ref as (ref this T item) but it won't compile :(... It would have been perfect.
Best I can offer you is the following syntax:
Setter.For( () => ObjectA );
using this helper class
static class Setter
{
public static Setter<T> For<T>(Expression<Func<T>> e)
{
ParameterExpression[] args = { Expression.Parameter(((e.Body as MemberExpression).Member as FieldInfo).FieldType) };
Action<T> s = Expression.Lambda<Action<T>>(Expression.Assign(e.Body, args[0]), args).Compile();
return new Setter<T>(s);
}
}