Related
Example:
Dim test2 As Func(Of String, Integer) = Function(xuy As String) xuy.Length * 2
Debug.WriteLine(test2.Method.Name)
Result: _Lambda$__22-0
How to name lambda function?
I'm creating manager for code-inline functions and i need to name them somehow. I know you can add additional parameter to parameter list as name but this is crutch.
In python you can directly name lambda func:
myfunc_l = lambda: None
myfunc_l.__name__ = 'foo'
But in .Net this property is ReadOnly.
Lambda functions, both in C# and in VB.NET are compiled to methods that are put in a hidden class. What you are seeing is the name of the method. You can't change it, you can't assign it, you can't even be sure the name will be the same between compilations (the names are autogenerated based on the "order" of the lambda functions).
SharpLab example in VB.NET:
This:
Public Class C
Public Sub M()
Dim test2 As Func(Of String, Integer) = Function(xuy As String) xuy.Length * 2
End Sub
End Class
is compiled to something that if decompiled in C# is:
[Serializable]
[CompilerGenerated]
internal sealed class _Closure$__
{
public static readonly _Closure$__ $I;
public static Func<string, int> $I1-0;
static _Closure$__()
{
$I = new _Closure$__();
}
internal int _Lambda$__1-0(string xuy)
{
return checked(xuy.Length * 2);
}
}
public void M()
{
if (_Closure$__.$I1-0 != null)
{
Func<string, int> $I1- = _Closure$__.$I1-0;
}
else
{
_Closure$__.$I1-0 = new Func<string, int>(_Closure$__.$I._Lambda$__1-0);
}
}
And SharpLab example in C#:
This:
public class C {
public void M() {
Func<String, int> test2 = xuy => xuy.Length * 2;
}
}
is compiled to this:
public class C
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Func<string, int> <>9__0_0;
internal int <M>b__0_0(string xuy)
{
return xuy.Length * 2;
}
}
public void M()
{
if (<>c.<>9__0_0 == null)
{
<>c.<>9__0_0 = new Func<string, int>(<>c.<>9.<M>b__0_0);
}
}
}
In both cases the hidden class introduced is quite easy to see.
I have a class called GenericItem (first time using generics), suppose i wanted to multiply two items if they were of the type integer, as you can see I am trying it in the method returnCounterMultiply, but it does not allow me to multiply them although i am trying to convert them and also checking if they are of type integer.
namespace Components
{
public class GenericItem<T>
{
private T data;
private T counter;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem(){}
public GenericItem(T _data)
{
data = _data;
}
public T returnCounterMultiply(T value)
{
int c = 0;
int d = 0;
if (counter.GetType() == typeof(int) && value.GetType() == typeof(int))
{
//cant multiply two of type T, why if i am converting to int?.
return (T)Convert.ChangeType(counter, typeof(Int32)) * (T)Convert.ChangeType(value, typeof(Int32));
}
return value;
}
}
}
I would appreciate some explanation on this as this is the first time I am working on it (this is just a sample class for understanding this GENERICS INTRO and this GENERICS CLASSES, but still having trouble understanding it.
I don't see what your trying to achieve, but if you have to do it I think you have to use an interface:
public interface IMultiplyable<T>
{
T Multiply(T x);
}
public class Int : IMultiplyable<Int>
{
private int _data { get; set; }
public Int(int data)
{
_data = data;
}
public Int Multiply(Int x)
{
return new Int(_data * x._data);
}
public override string ToString()
{
return _data.ToString();
}
}
public class GenericItem<T> where T : IMultiplyable<T>
{
private T data;
private T counter;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem() { }
public GenericItem(T _data)
{
data = _data;
}
public T returnCounterMultiply(T value)
{
return Data.Multiply(value);
}
public override string ToString()
{
return Data.ToString();
}
}
Usage:
var a = new GenericItem<Int>(new Int(4));
MessageBox.Show(a.returnCounterMultiply(new Int(5)).ToString()); //20
In my opinion, using generics in this case is an overkill.
It would be nice that generic constraints support something like:
// T parameter is a type which overloads "+" operator...
where T : +
In your concrete case, I would argue you're going in the wrong way. Why don't you just create a class to implement such math operations where properties are typed as int?
Generics work better when T parameter (or any other parameter, of course...) can be constrained to receive types which have:
A public parameterless constructor.
Inherits or implements a class/interface
You need to constraint that T must be a class and not a struct...
When you go into a problem when using generics requires a type conversion, I believe you defeated the point of generics!
You can do something like this:
public class GenericItem<T>
{
private T data;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem(){}
public GenericItem(T _data)
{
data = _data;
}
private Dictionary<Type, Delegate> operations =
new Dictionary<Type, Delegate>()
{
{ typeof(int), (Func<int, int, int>)((x, y) => x * y) },
{ typeof(string), (Func<string, string, string>)((x, y) => x + " " + y) },
};
public T returnCounterMultiply(T value)
{
if (operations.ContainsKey(typeof(T)))
{
var operation = (Func<T, T, T>)(operations[typeof(T)]);
return operation(data, value);
}
return value;
}
}
You just need to define, in the dictionary, one operation per valid types you're going to want to use and it just works without any converting of types (except to cast to the Func).
I had these test results:
var gii = new GenericItem<int>(42);
var xi = gii.returnCounterMultiply(2);
// xi == 84
var gis = new GenericItem<string>("Foo");
var xs = gis.returnCounterMultiply("Bar");
// xs == "Foo Bar"
Your problem has nothing to do with generics but with basic C# casting priority:
//cant multiply two of type T, why if i am converting to int?.
return
(T)Convert.ChangeType(counter, typeof(Int32))
*
(T)Convert.ChangeType(value,typeof(Int32));
You do not multiply int but T - and T being a generic type you can only use methods that are ddefined in your generics contraint, which you have none, so no multiply on it.
If you want to multiply int, then do so:
(T) (
((Int32)Convert.ChangeType(counter, typeof(Int32)))
*
((Int32)Convert.ChangeType(value,typeof(Int32)))
);
See the difference?
Basically in your code you deal with T in the multiplication, here I deal with Int32. And factually if T is a Int32 (as you tested before in the IF statement) you can just skip the convert and cast:
(T) (
((Int32)counter)
*
((Int32)value)
);
Now, generics are a bad example for maths as you can not use operations on generics - sadly. This is an abuse of the concept, but I take it was meant as a learning exercise and thus focused on that part on my answer.
I too tried this once and had to find out that there is no pretty way to do it with generics. You cannot do it as generic as in C++.
As an alternative, you may wrap your data types and use a common interface:
interface IMathOps
{
object Value { get; }
void Add(IMathOps other);
// other methods for substraction etc.
}
class IntWrapper : IMathOps
{
public int value;
public void Add(IMathOps other)
{
if(other is IntWrapper)
{
this.value += (int)other.Value;
}
}
public object Value { get { return this.value; } }
}
// class FloatWrapper : IMathOps ...
I think you should use where (generic type constraint). So it will give error at compile time if T is not int.
public T returnCounterMultiply(T value) where T : int
{
int c = 0;
int d = 0;
return c*d;
}
Is there a well-known way for simulating the variadic template feature in C#?
For instance, I'd like to write a method that takes a lambda with an arbitrary set of parameters. Here is in pseudo code what I'd like to have:
void MyMethod<T1,T2,...,TReturn>(Fun<T1,T2, ..., TReturn> f)
{
}
C# generics are not the same as C++ templates. C++ templates are expanded compiletime and can be used recursively with variadic template arguments. The C++ template expansion is actually Turing Complete, so there is no theoretically limit to what can be done in templates.
C# generics are compiled directly, with an empty "placeholder" for the type that will be used at runtime.
To accept a lambda taking any number of arguments you would either have to generate a lot of overloads (through a code generator) or accept a LambdaExpression.
There is no varadic support for generic type arguments (on either methods or types). You will have to add lots of overloads.
varadic support is only available for arrays, via params, i.e.
void Foo(string key, params int[] values) {...}
Improtantly - how would you even refer to those various T* to write a generic method? Perhaps your best option is to take a Type[] or similar (depending on the context).
I know this is an old question, but if all you want to do is something simple like print those types out, you can do this very easily without Tuple or anything extra using 'dynamic':
private static void PrintTypes(params dynamic[] args)
{
foreach (var arg in args)
{
Console.WriteLine(arg.GetType());
}
}
static void Main(string[] args)
{
PrintTypes(1,1.0,"hello");
Console.ReadKey();
}
Will print "System.Int32" , "System.Double", "System.String"
If you want to perform some action on these things, as far as I know you have two choices. One is to trust the programmer that these types can do a compatible action, for example if you wanted to make a method to Sum any number of parameters. You could write a method like the following saying how you want to receive the result and the only prerequisite I guess would be that the + operation works between these types:
private static void AddToFirst<T>(ref T first, params dynamic[] args)
{
foreach (var arg in args)
{
first += arg;
}
}
static void Main(string[] args)
{
int x = 0;
AddToFirst(ref x,1,1.5,2.0,3.5,2);
Console.WriteLine(x);
double y = 0;
AddToFirst(ref y, 1, 1.5, 2.0, 3.5, 2);
Console.WriteLine(y);
Console.ReadKey();
}
With this, the output for the first line would be "9" because adding to an int, and the second line would be "10" because the .5s didn't get rounded, adding as a double. The problem with this code is if you pass some incompatible type in the list, it will have an error because the types can't get added together, and you won't see that error at compile time, only at runtime.
So, depending on your use case there might be another option which is why I said there were two choices at first. Assuming you know the choices for the possible types, you could make an interface or abstract class and make all of those types implement the interface. For example, the following. Sorry this is a bit crazy. And it can probably be simplfied.
public interface Applyable<T>
{
void Apply(T input);
T GetValue();
}
public abstract class Convertable<T>
{
public dynamic value { get; set; }
public Convertable(dynamic value)
{
this.value = value;
}
public abstract T GetConvertedValue();
}
public class IntableInt : Convertable<int>, Applyable<int>
{
public IntableInt(int value) : base(value) {}
public override int GetConvertedValue()
{
return value;
}
public void Apply(int input)
{
value += input;
}
public int GetValue()
{
return value;
}
}
public class IntableDouble : Convertable<int>
{
public IntableDouble(double value) : base(value) {}
public override int GetConvertedValue()
{
return (int) value;
}
}
public class IntableString : Convertable<int>
{
public IntableString(string value) : base(value) {}
public override int GetConvertedValue()
{
// If it can't be parsed return zero
int result;
return int.TryParse(value, out result) ? result : 0;
}
}
private static void ApplyToFirst<TResult>(ref Applyable<TResult> first, params Convertable<TResult>[] args)
{
foreach (var arg in args)
{
first.Apply(arg.GetConvertedValue());
}
}
static void Main(string[] args)
{
Applyable<int> result = new IntableInt(0);
IntableInt myInt = new IntableInt(1);
IntableDouble myDouble1 = new IntableDouble(1.5);
IntableDouble myDouble2 = new IntableDouble(2.0);
IntableDouble myDouble3 = new IntableDouble(3.5);
IntableString myString = new IntableString("2");
ApplyToFirst(ref result, myInt, myDouble1, myDouble2, myDouble3, myString);
Console.WriteLine(result.GetValue());
Console.ReadKey();
}
Will output "9" the same as the original Int code, except the only values you can actually pass in as parameters are things that you actually have defined and you know will work and not cause any errors. Of course, you would have to make new classes i.e. DoubleableInt , DoubleableString, etc.. in order to re-create the 2nd result of 10. But this is just an example, so you wouldn't even be trying to add things at all depending on what code you are writing and you would just start out with the implementation that served you the best.
Hopefully someone can improve on what I wrote here or use it to see how this can be done in C#.
Another alternative besides those mentioned above is to use Tuple<,> and reflection, for example:
class PrintVariadic<T>
{
public T Value { get; set; }
public void Print()
{
InnerPrint(Value);
}
static void InnerPrint<Tn>(Tn t)
{
var type = t.GetType();
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Tuple<,>))
{
var i1 = type.GetProperty("Item1").GetValue(t, new object[]{});
var i2 = type.GetProperty("Item2").GetValue(t, new object[]{ });
InnerPrint(i1);
InnerPrint(i2);
return;
}
Console.WriteLine(t.GetType());
}
}
class Program
{
static void Main(string[] args)
{
var v = new PrintVariadic<Tuple<
int, Tuple<
string, Tuple<
double,
long>>>>();
v.Value = Tuple.Create(
1, Tuple.Create(
"s", Tuple.Create(
4.0,
4L)));
v.Print();
Console.ReadKey();
}
}
I don't necessarily know if there's a name for this pattern, but I arrived at the following formulation for a recursive generic interface that allows an unlimited amount of values to be passed in, with the returned type retaining type information for all passed values.
public interface ITraversalRoot<TRoot>
{
ITraversalSpecification<TRoot> Specify();
}
public interface ITraverser<TRoot, TCurrent>: ITraversalRoot<TRoot>
{
IDerivedTraverser<TRoot, TInclude, TCurrent, ITraverser<TRoot, TCurrent>> AndInclude<TInclude>(Expression<Func<TCurrent, TInclude>> path);
}
public interface IDerivedTraverser<TRoot, TDerived, TParent, out TParentTraverser> : ITraverser<TRoot, TParent>
{
IDerivedTraverser<TRoot, TInclude, TDerived, IDerivedTraverser<TRoot, TDerived, TParent, TParentTraverser>> FromWhichInclude<TInclude>(Expression<Func<TDerived, TInclude>> path);
TParentTraverser ThenBackToParent();
}
There's no casting or "cheating" of the type system involved here: you can keep stacking on more values and the inferred return type keeps storing more and more information. Here is what the usage looks like:
var spec = Traversal
.StartFrom<VirtualMachine>() // ITraverser<VirtualMachine, VirtualMachine>
.AndInclude(vm => vm.EnvironmentBrowser) // IDerivedTraverser<VirtualMachine, EnvironmentBrowser, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>
.AndInclude(vm => vm.Datastore) // IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>
.FromWhichInclude(ds => ds.Browser) // IDerivedTraverser<VirtualMachine, HostDatastoreBrowser, Datastore, IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>>
.FromWhichInclude(br => br.Mountpoints) // IDerivedTraverser<VirtualMachine, Mountpoint, HostDatastoreBrowser, IDerivedTraverser<VirtualMachine, HostDatastoreBrowser, Datastore, IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>>>
.Specify(); // ITraversalSpecification<VirtualMachine>
As you can see the type signature becomes basically unreadable near after a few chained calls, but this is fine so long as type inference works and suggests the right type to the user.
In my example I am dealing with Funcs arguments, but you could presumably adapt this code to deal with arguments of arbitrary type.
For a simulation you can say:
void MyMethod<TSource, TResult>(Func<TSource, TResult> f) where TSource : Tparams {
where Tparams to be a variadic arguments implementation class. However, the framework does not provide an out-of-box stuff to do that, Action, Func, Tuple, etc., are all have limited length of their signatures. The only thing I can think of is to apply the CRTP .. in a way I've not find somebody blogged. Here's my implementation:
*: Thank #SLaks for mentioning Tuple<T1, ..., T7, TRest> also works in a recursive way. I noticed it's recursive on the constructor and the factory method instead of its class definition; and do a runtime type checking of the last argument of type TRest is required to be a ITupleInternal; and this works a bit differently.
Code
using System;
namespace VariadicGenerics {
public interface INode {
INode Next {
get;
}
}
public interface INode<R>:INode {
R Value {
get; set;
}
}
public abstract class Tparams {
public static C<TValue> V<TValue>(TValue x) {
return new T<TValue>(x);
}
}
public class T<P>:C<P> {
public T(P x) : base(x) {
}
}
public abstract class C<R>:Tparams, INode<R> {
public class T<P>:C<T<P>>, INode<P> {
public T(C<R> node, P x) {
if(node is R) {
Next=(R)(node as object);
}
else {
Next=(node as INode<R>).Value;
}
Value=x;
}
public T() {
if(Extensions.TypeIs(typeof(R), typeof(C<>.T<>))) {
Next=(R)Activator.CreateInstance(typeof(R));
}
}
public R Next {
private set;
get;
}
public P Value {
get; set;
}
INode INode.Next {
get {
return this.Next as INode;
}
}
}
public new T<TValue> V<TValue>(TValue x) {
return new T<TValue>(this, x);
}
public int GetLength() {
return m_expandedArguments.Length;
}
public C(R x) {
(this as INode<R>).Value=x;
}
C() {
}
static C() {
m_expandedArguments=Extensions.GetExpandedGenericArguments(typeof(R));
}
// demonstration of non-recursive traversal
public INode this[int index] {
get {
var count = m_expandedArguments.Length;
for(INode node = this; null!=node; node=node.Next) {
if(--count==index) {
return node;
}
}
throw new ArgumentOutOfRangeException("index");
}
}
R INode<R>.Value {
get; set;
}
INode INode.Next {
get {
return null;
}
}
static readonly Type[] m_expandedArguments;
}
}
Note the type parameter for the inherited class C<> in the declaration of
public class T<P>:C<T<P>>, INode<P> {
is T<P>, and the class T<P> is nested so that you can do some crazy things such as:
Test
[Microsoft.VisualStudio.TestTools.UnitTesting.TestClass]
public class TestClass {
void MyMethod<TSource, TResult>(Func<TSource, TResult> f) where TSource : Tparams {
T<byte>.T<char>.T<uint>.T<long>.
T<byte>.T<char>.T<long>.T<uint>.
T<byte>.T<long>.T<char>.T<uint>.
T<long>.T<byte>.T<char>.T<uint>.
T<long>.T<byte>.T<uint>.T<char>.
T<byte>.T<long>.T<uint>.T<char>.
T<byte>.T<uint>.T<long>.T<char>.
T<byte>.T<uint>.T<char>.T<long>.
T<uint>.T<byte>.T<char>.T<long>.
T<uint>.T<byte>.T<long>.T<char>.
T<uint>.T<long>.T<byte>.T<char>.
T<long>.T<uint>.T<byte>.T<char>.
T<long>.T<uint>.T<char>.T<byte>.
T<uint>.T<long>.T<char>.T<byte>.
T<uint>.T<char>.T<long>.T<byte>.
T<uint>.T<char>.T<byte>.T<long>.
T<char>.T<uint>.T<byte>.T<long>.
T<char>.T<uint>.T<long>.T<byte>.
T<char>.T<long>.T<uint>.T<byte>.
T<long>.T<char>.T<uint>.T<byte>.
T<long>.T<char>.T<byte>.T<uint>.
T<char>.T<long>.T<byte>.T<uint>.
T<char>.T<byte>.T<long>.T<uint>.
T<char>.T<byte>.T<uint>.T<long>
crazy = Tparams
// trying to change any value to not match the
// declaring type makes the compilation fail
.V((byte)1).V('2').V(4u).V(8L)
.V((byte)1).V('2').V(8L).V(4u)
.V((byte)1).V(8L).V('2').V(4u)
.V(8L).V((byte)1).V('2').V(4u)
.V(8L).V((byte)1).V(4u).V('2')
.V((byte)1).V(8L).V(4u).V('2')
.V((byte)1).V(4u).V(8L).V('2')
.V((byte)1).V(4u).V('2').V(8L)
.V(4u).V((byte)1).V('2').V(8L)
.V(4u).V((byte)1).V(8L).V('2')
.V(4u).V(8L).V((byte)1).V('2')
.V(8L).V(4u).V((byte)1).V('2')
.V(8L).V(4u).V('9').V((byte)1)
.V(4u).V(8L).V('2').V((byte)1)
.V(4u).V('2').V(8L).V((byte)1)
.V(4u).V('2').V((byte)1).V(8L)
.V('2').V(4u).V((byte)1).V(8L)
.V('2').V(4u).V(8L).V((byte)1)
.V('2').V(8L).V(4u).V((byte)1)
.V(8L).V('2').V(4u).V((byte)1)
.V(8L).V('2').V((byte)1).V(4u)
.V('2').V(8L).V((byte)1).V(4u)
.V('2').V((byte)1).V(8L).V(4u)
.V('7').V((byte)1).V(4u).V(8L);
var args = crazy as TSource;
if(null!=args) {
f(args);
}
}
[TestMethod]
public void TestMethod() {
Func<
T<byte>.T<char>.T<uint>.T<long>.
T<byte>.T<char>.T<long>.T<uint>.
T<byte>.T<long>.T<char>.T<uint>.
T<long>.T<byte>.T<char>.T<uint>.
T<long>.T<byte>.T<uint>.T<char>.
T<byte>.T<long>.T<uint>.T<char>.
T<byte>.T<uint>.T<long>.T<char>.
T<byte>.T<uint>.T<char>.T<long>.
T<uint>.T<byte>.T<char>.T<long>.
T<uint>.T<byte>.T<long>.T<char>.
T<uint>.T<long>.T<byte>.T<char>.
T<long>.T<uint>.T<byte>.T<char>.
T<long>.T<uint>.T<char>.T<byte>.
T<uint>.T<long>.T<char>.T<byte>.
T<uint>.T<char>.T<long>.T<byte>.
T<uint>.T<char>.T<byte>.T<long>.
T<char>.T<uint>.T<byte>.T<long>.
T<char>.T<uint>.T<long>.T<byte>.
T<char>.T<long>.T<uint>.T<byte>.
T<long>.T<char>.T<uint>.T<byte>.
T<long>.T<char>.T<byte>.T<uint>.
T<char>.T<long>.T<byte>.T<uint>.
T<char>.T<byte>.T<long>.T<uint>.
T<char>.T<byte>.T<uint>.T<long>, String>
f = args => {
Debug.WriteLine(String.Format("Length={0}", args.GetLength()));
// print fourth value from the last
Debug.WriteLine(String.Format("value={0}", args.Next.Next.Next.Value));
args.Next.Next.Next.Value='x';
Debug.WriteLine(String.Format("value={0}", args.Next.Next.Next.Value));
return "test";
};
MyMethod(f);
}
}
Another thing to note is we have two classes named T, the non-nested T:
public class T<P>:C<P> {
is just for the consistency of usage, and I made class C abstract to not directly being newed.
The Code part above needs to expand ther generic argument to calculate about their length, here are two extension methods it used:
Code(extensions)
using System.Diagnostics;
using System;
namespace VariadicGenerics {
[DebuggerStepThrough]
public static class Extensions {
public static readonly Type VariadicType = typeof(C<>.T<>);
public static bool TypeIs(this Type x, Type d) {
if(null==d) {
return false;
}
for(var c = x; null!=c; c=c.BaseType) {
var a = c.GetInterfaces();
for(var i = a.Length; i-->=0;) {
var t = i<0 ? c : a[i];
if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
return true;
}
}
}
return false;
}
public static Type[] GetExpandedGenericArguments(this Type t) {
var expanded = new Type[] { };
for(var skip = 1; t.TypeIs(VariadicType) ? true : skip-->0;) {
var args = skip>0 ? t.GetGenericArguments() : new[] { t };
if(args.Length>0) {
var length = args.Length-skip;
var temp = new Type[length+expanded.Length];
Array.Copy(args, skip, temp, 0, length);
Array.Copy(expanded, 0, temp, length, expanded.Length);
expanded=temp;
t=args[0];
}
}
return expanded;
}
}
}
For this implementation, I choosed not to break the compile-time type checking, so we do not have a constructor or a factory with the signature like params object[] to provide values; instead, use a fluent pattern of method V for mass object instantiation to keep type can be statically type checked as much as possible.
I am working on a generic utility method that takes a generic argument and returns a generic type--I hope that makes sense!--but I want the return type to be a different type from the argument.
Here's what I'm thinking this should look like if I mock it up in pseudo code:
public static IEnumerable<R> DoSomethingAwesome<T>(T thing)
{
var results = new List<R>();
for (int xx = 0; xx < 5; xx++)
{
results.Add(thing.ToRType(xx));
}
return results;
}
With generics not being able to infer the return type how would I go about doing something like this? So far, my Google-Fu has failed me.
// You need this to constrain T in your method and call ToRType()
public interface IConvertableToTReturn
{
object ToRType(int someInt);
}
public static IEnumerable<TReturn> DoSomethingAwesome<T, TReturn>(T thing)
where T : IConvertableToTReturn
{
Enumerable.Range(0, 5).Select(xx => thing.ToRType(xx));
}
You can pass the return class as an output parameter:
public static void DoSomethingAwesome<T,R>(T thing, out IEnumerable<R> output)
This can then be inferred.
static IEnumerable<R> Function<T,R> (T h)
{
for (int xx = 0; xx < 5; xx++)
{
yield return h.ToRType(xx);
}
yield return break;
}
IEnumerable<class2> res = Function<class1, class2>(class1Object);
You need to explicitly specify the return generic type as a type parameter to the method.
Something like:
public static IEnumerable<R> DoSomething<T,R>(IEnumerable<T> things, Func<T,R> map)
{
foreach (var t in things) { yield return map(t); }
}
This is essentially what the Linq IEnumerable extension method "Select" does..
Generics can be awesome and a pretty awesome pain. As other have stated you can use a variety of ways to have multiple in put parameters the real trick is in doing something usefully with the passed in types.
in Your example
public static IEnumerable<Ret> Fn<Ret,Parm>(IList<Parm> P)
{
var Results = new List<Ret>();
foreach(Parm p in P)
{
Results.Add(p.ToType());
}
return Results;
}
Will not complie since the complier doesn't know what to do with P.ToType()
So you say well I can just add the function needed to my param type But that doesn't work either since the complier again doesn't know what the concrete version or Ret will be and your return list is of type Ret not of type returnType
public class RetunType
{
public int a;
}
public class Input
{
public int x;
public RetunType TotoAReturnType()
{
return new RetunType() { a = this.x };
}
}
public static IEnumerable<Ret> Fn<Ret, Parm>(IList<Parm> P) where Parm : Input where Ret:RetunType
{
var Results = new List<Ret>();
foreach (Parm p in P)
{
Results.Add(p.TotoAReturnType());
}
return Results;
}
To solve this issue you can add a generic interface so that your function can work if any type supports the generic interface
Like this
public interface ToType<R>
{
R ToType();
}
public class B
{
public int x;
}
public class A : ToType<B>
{
string x = "5";
public B ToType()
{
B aB = new B();
aB.x = int.Parse(x);
return aB;
}
}
public static IEnumerable<Ret> Fn<Ret,Parm>(IList<Parm> P) where Parm : ToType<Ret>
{
var Results = new List<Ret>();
foreach(Parm p in P)
{
Results.Add(p.ToType());
}
return Results;
}
static void Main(string[] args)
{
List<A> inLst = new List<A>() { new A()};
var lst = Fn<B, A>(inLst);
}
Generics are awesome but I would strongly suggest looking to using interfaces to support you actions in those functions.
I'm working with reflection and currently have a MethodBody. How do I check if a specific method is called inside the MethodBody?
Assembly assembly = Assembly.Load("Module1");
Type type = assembly.GetType("Module1.ModuleInit");
MethodInfo mi = type.GetMethod("Initialize");
MethodBody mb = mi.GetMethodBody();
Use Mono.Cecil. It is a single standalone assembly that will work on Microsoft .NET as well as Mono. (I think I used version 0.6 or thereabouts back when I wrote the code below)
Say you have a number of assemblies
IEnumerable<AssemblyDefinition> assemblies;
Get these using AssemblyFactory (load one?)
The following snippet would enumerate all usages of methods in all types of these assemblies
methodUsages = assemblies
.SelectMany(assembly => assembly.MainModule.Types.Cast<TypeDefinition>())
.SelectMany(type => type.Methods.Cast<MethodDefinition>())
.Where(method => null != method.Body) // allow abstracts and generics
.SelectMany(method => method.Body.Instructions.Cast<Instruction>())
.Select(instr => instr.Operand)
.OfType<MethodReference>();
This will return all references to methods (so including use in reflection, or to construct expressions which may or may not be executed). As such, this is probably not very useful, except to show you what can be done with the Cecil API without too much of an effort :)
Note that this sample assumes a somewhat older version of Cecil (the one in mainstream mono versions). Newer versions are
more succinct (by using strong typed generic collections)
faster
Of course in your case you could have a single method reference as starting point. Say you want to detect when 'mytargetmethod' can actually be called directly inside 'startingpoint':
MethodReference startingpoint; // get it somewhere using Cecil
MethodReference mytargetmethod; // what you are looking for
bool isCalled = startingpoint
.GetOriginalMethod() // jump to original (for generics e.g.)
.Resolve() // get the definition from the IL image
.Body.Instructions.Cast<Instruction>()
.Any(i => i.OpCode == OpCodes.Callvirt && i.Operand == (mytargetmethod));
Call Tree Search
Here is a working snippet that allows you to recursively search to (selected) methods that call each other (indirectly).
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace StackOverflow
{
/*
* breadth-first lazy search across a subset of the call tree rooting in startingPoint
*
* methodSelect selects the methods to recurse into
* resultGen generates the result objects to be returned by the enumerator
*
*/
class CallTreeSearch<T> : BaseCodeVisitor, IEnumerable<T> where T : class
{
private readonly Func<MethodReference, bool> _methodSelect;
private readonly Func<Instruction, Stack<MethodReference>, T> _transform;
private readonly IEnumerable<MethodDefinition> _startingPoints;
private readonly IDictionary<MethodDefinition, Stack<MethodReference>> _chain = new Dictionary<MethodDefinition, Stack<MethodReference>>();
private readonly ICollection<MethodDefinition> _seen = new HashSet<MethodDefinition>(new CompareMembers<MethodDefinition>());
private readonly ICollection<T> _results = new HashSet<T>();
private Stack<MethodReference> _currentStack;
private const int InfiniteRecursion = -1;
private readonly int _maxrecursiondepth;
private bool _busy;
public CallTreeSearch(IEnumerable<MethodDefinition> startingPoints,
Func<MethodReference, bool> methodSelect,
Func<Instruction, Stack<MethodReference>, T> resultGen)
: this(startingPoints, methodSelect, resultGen, InfiniteRecursion)
{
}
public CallTreeSearch(IEnumerable<MethodDefinition> startingPoints,
Func<MethodReference, bool> methodSelect,
Func<Instruction, Stack<MethodReference>, T> resultGen,
int maxrecursiondepth)
{
_startingPoints = startingPoints.ToList();
_methodSelect = methodSelect;
_maxrecursiondepth = maxrecursiondepth;
_transform = resultGen;
}
public override void VisitMethodBody(MethodBody body)
{
_seen.Add(body.Method); // avoid infinite recursion
base.VisitMethodBody(body);
}
public override void VisitInstructionCollection(InstructionCollection instructions)
{
foreach (Instruction instr in instructions)
VisitInstruction(instr);
base.VisitInstructionCollection(instructions);
}
public override void VisitInstruction(Instruction instr)
{
T result = _transform(instr, _currentStack);
if (result != null)
_results.Add(result);
var methodRef = instr.Operand as MethodReference; // TODO select calls only?
if (methodRef != null && _methodSelect(methodRef))
{
var resolve = methodRef.Resolve();
if (null != resolve && !(_chain.ContainsKey(resolve) || _seen.Contains(resolve)))
_chain.Add(resolve, new Stack<MethodReference>(_currentStack.Reverse()));
}
base.VisitInstruction(instr);
}
public IEnumerator<T> GetEnumerator()
{
lock (this) // not multithread safe
{
if (_busy)
throw new InvalidOperationException("CallTreeSearch enumerator is not reentrant");
_busy = true;
try
{
int recursionLevel = 0;
ResetToStartingPoints();
while (_chain.Count > 0 &&
((InfiniteRecursion == _maxrecursiondepth) || recursionLevel++ <= _maxrecursiondepth))
{
// swapout the collection because Visitor will modify
var clone = new Dictionary<MethodDefinition, Stack<MethodReference>>(_chain);
_chain.Clear();
foreach (var call in clone.Where(call => HasBody(call.Key)))
{
// Console.Error.Write("\rCallTreeSearch: level #{0}, scanning {1,-20}\r", recursionLevel, call.Key.Name + new string(' ',21));
_currentStack = call.Value;
_currentStack.Push(call.Key);
try
{
_results.Clear();
call.Key.Body.Accept(this); // grows _chain and _results
}
finally
{
_currentStack.Pop();
}
_currentStack = null;
foreach (var result in _results)
yield return result;
}
}
}
finally
{
_busy = false;
}
}
}
private void ResetToStartingPoints()
{
_chain.Clear();
_seen.Clear();
foreach (var startingPoint in _startingPoints)
{
_chain.Add(startingPoint, new Stack<MethodReference>());
_seen.Add(startingPoint);
}
}
private static bool HasBody(MethodDefinition methodDefinition)
{
return !(methodDefinition.IsAbstract || methodDefinition.Body == null);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
internal class CompareMembers<T> : IComparer<T>, IEqualityComparer<T>
where T: class, IMemberReference
{
public int Compare(T x, T y)
{ return StringComparer.InvariantCultureIgnoreCase.Compare(KeyFor(x), KeyFor(y)); }
public bool Equals(T x, T y)
{ return KeyFor(x).Equals(KeyFor(y)); }
private static string KeyFor(T mr)
{ return null == mr ? "" : String.Format("{0}::{1}", mr.DeclaringType.FullName, mr.Name); }
public int GetHashCode(T obj)
{ return KeyFor(obj).GetHashCode(); }
}
}
Notes
do some error handling a Resolve() (I have an extension method TryResolve() for the purpose)
optionally select usages of MethodReferences in a call operation (call, calli, callvirt ...) only (see //TODO)
Typical usage:
public static IEnumerable<T> SearchCallTree<T>(this TypeDefinition startingClass,
Func<MethodReference, bool> methodSelect,
Func<Instruction, Stack<MethodReference>, T> resultFunc,
int maxdepth)
where T : class
{
return new CallTreeSearch<T>(startingClass.Methods.Cast<MethodDefinition>(), methodSelect, resultFunc, maxdepth);
}
public static IEnumerable<T> SearchCallTree<T>(this MethodDefinition startingMethod,
Func<MethodReference, bool> methodSelect,
Func<Instruction, Stack<MethodReference>, T> resultFunc,
int maxdepth)
where T : class
{
return new CallTreeSearch<T>(new[] { startingMethod }, methodSelect, resultFunc, maxdepth);
}
// Actual usage:
private static IEnumerable<TypeUsage> SearchMessages(TypeDefinition uiType, bool onlyConstructions)
{
return uiType.SearchCallTree(IsBusinessCall,
(instruction, stack) => DetectRequestUsage(instruction, stack, onlyConstructions));
}
Note the completiion of a function like DetectRequestUsage to suite your needs is completely and entirely up to you (edit: but see here). You can do whatever you want, and don't forget: you'll have the complete statically analyzed call stack at your disposal, so you actually can do pretty neat things with all that information!
Before it generates code, it must check if it already exists
There are a few cases where catching an exception is way cheaper than preventing it from being generated. This is a prime example. You can get the IL for the method body but Reflection is not a disassembler. Nor is a disassembler a real fix, you'd have the disassemble the entire call tree to implement your desired behavior. After all, a method call in the body could itself call a method, etcetera. It is just much simpler to catch the exception that the jitter will throw when it compiles the IL.
One can use the StackTrace class:
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
System.Diagnostics.StackFrame sf = st.GetFrame(1);
Console.Out.Write(sf.GetMethod().ReflectedType.Name + "." + sf.GetMethod().Name);
The 1 can be adjusted and determines the number of frame you are interested in.