Can IronPython dynamically add methods to a C# class? - c#

I have some simple C# types that are used in an embedded IronPython script:
//simple type
public class Foo
{
public int a;
public int b;
}
var engine = IronPython.Hosting.Python.CreateEngine();
dynamic scope = engine.CreateScope();
scope.foo = new Foo{ a = 1, b = 2 };
engine.Execute( "print( foo.a )", scope );
I'd like to add some functionality to Foo but I cannot modify it's code. Also I'd rather not derive from it nor use extension methods, but use delegates instead. Ideally I'd like to write something like
scope.AddMemberFunction( scope.foo, "Fun",
new Func<Foo,int>( f => return f.a + f.b ) );
and then use it in the Python script directly:
print( foo.Fun() )
I thought this was exactly what could be done using the Operations but this raises an exception saying 'Foo' object has no attribute 'Fun'
engine.Operations.SetMember( scope.foo, "Fun",
new Func<Foo, int>( f => f.a + f.b ) );
Next I tried the Python way of things (say Foo is in a namespace IronPythonApp that is in and it's assembly is added to the engine.Runtime):
import IronPythonApp
def Fun( self ):
return self.a + self.b
IronPythonApp.Foo.Fun = Fun
but this gives a similar exception: can't set attributes of built-in/extension type 'Foo'
Is there a way to modify the Python class definition that ironPython internally generates?
Update
I explored some of the options as by Jeff Hardy's answer. Here are two ways that can both be made pretty scalable (just showing the straightforward way here)
ExpandoObject!
var foo = new Foo { a = 1, b = 2 };
dynamic exp = new ExpandoObject();
exp.Fun = new Func<int>( () => foo.a + foo.b );
exp.a = foo.a; //automating these is not a big deal
exp.b = foo.b; //
//now just add exp to the scope and done.
Using SetMember after all
scope.origFoo = new Foo { a = 1, b = 2 };
//the only variable thing in this string is 'origFoo'
//so it's no big deal scaling this
engine.Execute( #"
class GenericWrapper( object ) :
def __init__( self, foo ):
self.foo = foo
def __getattr__( self, name ) :
return getattr( self.foo, name )
foo = GenericWrapper( origFoo )", scope );
//ha, now scope contains something that we can mess with after all
engine.Operations.SetMember( scope.foo, "Fun",
new Func<int>( () => scope.foo.a + scope.foo.b ) );
engine.Execute( "print( foo.Fun() )", scope );

Short answer: nope, you can't modify a .NET class. By default, they don't have the necessary dynamic hooks to add members.
Your best bet is to wrap the class and add the members you want; Python makes this easy:
class FooWrapper(object):
def __init__(self, foo):
self.foo = foo
def __getattr__(self, name):
return getattr(self.foo, name)
def mymethod(self):
...
The __getattr__ special method is only called for attributes that are not part of normal attribute lookup, so mymethod() will be looked up normally but anything else will be forwarded to the underlying object.
If you need to do it on the C# side, you can achieve the same thing by subclassing DynamicObject and overloading the Try*Member functions.

Related

In C#, how can I create a value type variable at runtime?

I am attempting to implement a method like:
(Func<T> getFn, Action<T> setFn) MakePair<T>(T initialVal) {
}
It will return two runtime generated lambdas that get and set a dynamically created variable using Expression trees to create the code.
My current solution is to dynamically create an array of the type with one element, and reference that:
(Func<T> getFn, Action<T> setFn) MakePair<T>(T initialVal) {
var dynvar = Array.CreateInstance(typeof(T), 1);
Expression<Func<Array>> f = () => dynvar;
var dynref = Expression.Convert(f.Body, typeof(T).MakeArrayType());
var e0 = Expression.Constant(0);
var getBody = Expression.ArrayIndex(dynref, e0);
var setParam = Expression.Parameter(typeof(T));
var setBody = Expression.Assign(Expression.ArrayAccess(dynref, e0), setParam);
var getFn = Expression.Lambda<Func<T>>(getBody).Compile();
var setFn = Expression.Lambda<Action<T>>(setBody, setParam).Compile();
return (getFn, setFn);
}
Is there a better way to create what may be a value type variable at runtime that can be read/written to than using an array?
Is there a better way to reference the runtime created array other than using a lambda to create the (field?) reference for use in the ArrayIndex/ArrayAccess method calls?
Excessive Background Info
For those that wonder, ultimately this came up in an attempt to create something like Perl auto-virification of lvalues for Perl hashes.
Imagine you have a List<T> with duplicate elements and want to create a Dictionary<T,int> that allows you to look up the count for each unique T in the list. You can use a few lines of code to count (in this case T is int):
var countDict = new Dictionary<int, int>();
foreach (var n in testarray) {
countDict.TryGetValue(n, out int c);
countDict[n] = c + 1;
}
But I want to do this with LINQ, and I want to avoid double-indexing countDict (interestingly, ConcurrentDictionary has AddOrUpdate for this purpose) so I use Aggregate:
var countDict = testarray.Aggregate(new Dictionary<int,int>(), (d, n) => { ++d[n]; return d; });
But this has a couple of issues. First, Dictionary won't create a value for a missing value, so you need a new type of Dictionary that auto-creates missing values using e.g. a seed lambda:
var countDict = testarray.Aggregate(new SeedDictionary<int, Ref<int>>(() => Ref.Of(() => 0)), (d, n) => { var r = d[n]; ++r.Value; return d; });
But you still have the lvalue problem, so you replace the plain int counter with a Ref class. Unfortunately, C# can't create a C++ first class Ref class, but using one based around auto-creating a setter lambda from a getter lambda (using expression trees) is close enough. (Unfortunately C# still won't accept ++d[n].Value; even though it should be valid, so you have to create a temporary.)
But now you have the problem of creating multiple runtime integer variables to hold the counts. I extended the Ref<> class to take a lambda that returns a constant (ConstantExpression) and create a runtime variable and build a getter and setter with the constant being the initial value.
I agree with some of the question commenters that expression trees seem unnecessary, so here is a simple implementation of the shown API without them:
struct Box<T> {
public T Value;
}
(Func<T> getFn, Action<T> setFn) MakePair<T>(T initialVal) {
var box = new Box<T> { Value = initialVal };
return (() => box.Value, v => box.Value = v);
}
As an answer to the stated question (how to define dynref without a lambda), then, is there something wrong with the following modifications to dynvar and dynref?
var dynvar = new T[] { initialVal };
var dynref = Expression.Constant(dynvar);

Roslyn Resolved Syntax Tree without Workspaces

I am trying to use Roslyn to create a C# code editor. I would like to get a resolved syntax tree so that I can add code completion support.
However, I cannot use Workspaces since they are broken on iOS.
I am therefore trying to hit the C# compiler directly using Compilations (is this right?). The API is simple enough, but I cannot figure out how to get member information for types.
Specifically, I would like to see a Members property of the class C that includes a reference to the fully declared D class.
However, the INamedTypeSymbol doesn't have any useful info attached to it.
How do I get rich type info from a CSharpCompilation?
var cst = Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseCompilationUnit (
"public class C { public D foo; }");
var dst = Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseCompilationUnit (
"public class D { public C bar; }");
var comp = Microsoft.CodeAnalysis.CSharp.CSharpCompilation.
Create ("Poo").
AddSyntaxTrees (cst.SyntaxTree).
AddSyntaxTrees (dst.SyntaxTree);
var classC = comp.GetSymbolsWithName (n => n == "C").FirstOrDefault (); //= C
var classD = comp.GetSymbolsWithName (n => n == "D").FirstOrDefault (); //= D
var otherClassC = comp.GetTypeByMetadataName ("C"); //= C
Console.WriteLine ("C = " + classC);
You're looking for the GetMembers() method, which returns all declared members in the type.

Call function in dynamic linq

I'm trying to call a function in a dynamic linq select statement, but im getting error:
No property or field 'A' exists in type 'Tuple2'
Example code:
void Main()
{
var a = new Tuple<int, int>(1,1);
var b = new[]{ a };
var q = b.AsQueryable().Select("A.Test(it.Item1)");
q.Dump();
}
public static class A
{
public static int Test(int i)
{
return i++;
}
}
How should I change my code to get this working?
If I call built in function Convert.ToInt32 for example it works fine.
var q = b.AsQueryable().Select("Convert.ToInt32(it.Item1)");
Also how do I cast a property using dynamic linq?
var q = b.AsQueryable().Select("((float)it.Item1)");
I'll say that the dynamic-linq isn't "strong enough" to do these things. It looks for methods only in the given objects and some special classes: Math, Convert, the various base types (int, float, string, ...), Guid, Timespan, DateTime
The list of these types is clearly visible if you use ilspy/reflector on the file. They are in System.Linq.Dynamic.ExpressionParser.predefinedTypes .
Now, clearly I could be wrong, but this works: .Select("Guid.NewGuid().ToString()").Cast<string>().ToArray()
showing that it's quite probable that that is the "correct" list.
There is an article here on how to modify Dynamic LINQ if you are interested http://www.krizzcode.com/2012/01/extending-dynamiclinq-language.html
Now, an intelligent man would take the source of dynamic linq and simply expand that array... But here there aren't intelligent men... There are only programmers that want blood! Blood but especially innards!
var type = typeof(DynamicQueryable).Assembly.GetType("System.Linq.Dynamic.ExpressionParser");
FieldInfo field = type.GetField("predefinedTypes", BindingFlags.Static | BindingFlags.NonPublic);
Type[] predefinedTypes = (Type[])field.GetValue(null);
Array.Resize(ref predefinedTypes, predefinedTypes.Length + 1);
predefinedTypes[predefinedTypes.Length - 1] = typeof(A); // Your type
field.SetValue(null, predefinedTypes);
Do this (with the types you want) BEFORE the first call to Dynamic Linq (because after the first call the methods/properties of these types are cached)
Explanation: we use reflection to add our object(s) to this "special list".
I know there is already an accepted answer on this but it did not work for me. I am using Dynamic Linq 1.1.4. I wanted to do a query like this
$.GetNewestRisk() == null
Where GetNewestRisk() is a public method on the object represented by $. I kept getting this error "Error running query, Methods on type 'Patient' are not accessible (at index 2)".
I found in the source code there is a GlobalConfig object that allows a custom provider to be assigned which will hold all of the types you may want to work with. Here is the source code for the custom provider:
public class CustomTypeProvider: IDynamicLinkCustomTypeProvider
{
public HashSet<Type> GetCustomTypes()
{
HashSet<Type> types = new HashSet<Type>();
types.Add(typeof(Patient));
types.Add(typeof(RiskFactorResult));
types.Add(typeof(PatientLabResult));
types.Add(typeof(PatientVital));
return types;
}
}
Here is how I am using it:
System.Linq.Dynamic.GlobalConfig.CustomTypeProvider = new CustomType();
After making this call I am able to call methods on the objects inside of the expression.
#xanatos answer doesn't work for .Net Core version. So I've found something similar related by #Kent on the System.Dynamic.Linq.Core tests DynamicExpressionParserTests written by the library's author himself.
The given TestCustomTypeProviderClass allows you to use the DynamicLinqType class annotation which is pretty usefull for this problem.
To answer to question, you then just needed to defined the class (ensure to annotate with DynamicLinqType) :
[DynamicLinqType]
public static class A
{
public static int Test(int i)
{
return i++;
}
}
Add a customTypeProvider as mentioned above :
private class TestCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
{
private HashSet<Type> _customTypes;
public virtual HashSet<Type> GetCustomTypes()
{
if (_customTypes != null)
{
return _customTypes;
}
_customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly }));
return _customTypes;
}
}
and use a ParsingConfig with the configurable Select to call it :
var config = new ParsingConfig
{
CustomTypeProvider = new TestCustomTypeProvider()
};
var q = b.AsQueryable().Select(config, "A.Test(it.Item1)");
#Armand has put together a brilliant solution for this issue, and being the only solution I was able to find regarding this I want to add to it for anyone who tries the same approach.
The class that is marked with...
[DynamicLinqType]
... must be taken into consideration when you run the following line:
FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly })
In the solution provided above, this assumes the class that contains the function to be evaluated is on the same class the code currently resides in. If the methods are to be used outside of said class, the assembly will need to change.
FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { typeof(AnotherClassName).Assembly })
Nothing changes from the solution above, this is just for clarification for anyone attempting to use it.
As regards the current version (1.2.19) of Dynamic LINQ, you will probably get another exception:
System.Linq.Dynamic.Core.Exceptions.ParseException : Enum value 'Test' is not defined in enum type 'A'
To make DLINQ know your type 'A', you have two options:
Set up parsing config with your own custom types provider where you directly specify the type 'A'.
Mark your type with the attribute [DynamicLinqType]. If that type is loaded into the current domain (that's the usual case), you don't have to do anything more since the default custom type provider already scans the current AppDomain for types marked with [DynamicLinqType]. And only if that's not the case, i.e. your type is not loaded into the current domain, you have to do something like in that answer.
What if you would like to use both approaches - the first for type 'A' and the second for type 'B'? In that case, you just have to "merge" your type 'A' with the default provider types:
public class DynamicLinqTests
{
[Test]
public void Test()
{
var a = new Tuple<int, int>(1, 1);
var b = new[] { a };
var parsingConfig = new ParsingConfig
{
ResolveTypesBySimpleName = true,
CustomTypeProvider = new TestCustomTypesProvider()
};
var queryWithA = b.AsQueryable().Select(parsingConfig, "A.Test(it.Item1)");
queryWithA.ToDynamicList();
var queryWithB = b.AsQueryable().Select(parsingConfig, "B.Test(it.Item1)");
queryWithB.ToDynamicList();
}
public static class A
{
public static int Test(int i)
{
return i++;
}
}
[DynamicLinqType]
public static class B
{
public static int Test(int i)
{
return i++;
}
}
public class TestCustomTypesProvider : DefaultDynamicLinqCustomTypeProvider
{
public override HashSet<Type> GetCustomTypes()
{
var customTypes = base.GetCustomTypes();
customTypes.Add(typeof(A));
return customTypes;
}
}
}
I may be confused but your syntax whereby you are using a string in your Selects doesn't compile for me. The following syntax works:
var q = b.AsQueryable().Select(it => A.Test(it.Item1));
var b = new[]{ a };
The above array is don't know what type of array , and it's not type safe ?
Your values are assigned in variant data type so it's not integer value (I think string value) ,when you get this values in your query must need to convert.toint32() because your class parameter data type is integer
Please try it
var b = new **int**[]{ a };
instead of var b = new[]{ a };
The important hint is here (in bold):
No property or field 'xxx' exists in **type** 'xxx'
And Please look this for previous discussion :
Dynamic Linq - no property or field exists in type 'datarow'
The following works for me:
var a = new Tuple<int, int>(1, 1);
var b = new[] { a };
var q = b.AsQueryable().Select(it=>A.Test(it.Item1));
var q1 = b.AsQueryable().Select(it => Convert.ToInt32(it.Item1));
var q2 = b.AsQueryable().Select(it => (float) it.Item1);

Can I return a reference to new object instance from a C# delegate?

I'm learning/experimenting with some functional patterns within C# and I've hit a bump I can't quite explain. I'm sure it's a simple answer (I hope) but I'm struggling to see it. Likely has to do with closures, etc and my inability to get out-of-box is hiding the answer from me!
Here's my experiment: I'm trying to return a brand new instance of a particular class from within a function delegate..
public class Foo{
string A { get; set ; }
}
static void Main( string[] args ){
// the delegate...
Func<Foo,bool> someFunc = o => {
o = new Foo { A = "A new instance of o?" };
return true;
};
Foo foo = null; // was hoping to replace this via delegate
var myFunc = someFunc;
var result = myFunc( foo );
if ( foo == null )
Console.WriteLine( "foo unchanged :-(" );
else
Console.WriteLine( foo.A ); // hoping for 'A new instance of o?'
Of course, I just get "foo unchanged :-(" in my output.
I made a slight variation on the test where I passed in a non-null Foo instance and modified the property "A" (vs returning a new instance) and that worked okay (that is, I can mutate an existing object just like I would expect when passing object references to functions) I just can't seem to get a new instance out of my delegate.
So? Am I just doing something wrong in the code? Can this be done at all? Would love to understand why this doesn't work.
Formal parameter o is a copy of the value of foo; mutating o does not mutate foo. It's the same as when you say:
int x = 1;
int y = x;
y = 2;
That doesn't change x. y is a copy of the value of x, not an alias to x.
You're overthinking the problem. If you want to have a delegate that mutates a local then just write a delegate that mutates a local:
Foo foo = null; // was hoping to replace this via delegate
Action mutateFoo = () => { foo = new Foo() { A = "whatever"}; };
mutateFoo();
if ( foo == null )
Console.WriteLine( "foo unchanged :-(" );
else
Console.WriteLine( foo.A );
If all you want to do is mutate a variable then mutate the variable. There's no need to pass anything in or out from the delegate if you just want to perform a side effect.
I notice that you said that you were experimenting with functional patterns. Remember, functional programming discourages variable mutation, so you might be going down a false path here.
You can return the Foo as the return value of the lambda expression:
Func<Foo> someFunc = o =>
{
return new Foo { A = "A new instance of o?" };
};
Or you can return a Tuple<bool, Foo> if you really need to return a bool:
Func<Tuple<bool, Foo>> someFunc = o =>
{
return Tuple.Create(true, new Foo { A = "A new instance of o?" });
};
Or, if you're really really sure you want that, you can declare your own custom Func-like delegate with an out parameter:
delegate TResult FuncOut<T, TResult>(out T arg);
FuncOut<Foo, bool> someFunc = (out Foo o) =>
{
o = new Foo { A = "A new instance of o?" };
return true;
};
Foo foo;
var result = someFunc(out foo);
But I wouldn't recommend that.
You are passing reference (i.e. address) of Foo object to your delegate. That address is assigned to parameter o of delegate (consider it as local variable). When you are changing Foo object in delegate, then you are going to referenced object and changing what's sitting on that address. That's why object changes.
But when you are assigning new address to local variable of delegate (i.e. parameter), then you just losing address of original Foo object which was passed into delegate. After assignment local variable just holds address of new Foo object. It does not affect foo variable of caller, which still holds another address.

C# equivalent for Visual Basic keyword: 'With' ... 'End With'?

In Visual Basic, if you are going to change multiple properties of a single object, there's a With/End With statement:
Dim myObject as Object
// ' Rather than writing:
myObject.property1 = something
myObject.property2 = something2
// ' You can write:
with myObject
.property1 = something
.property2 = something2
...
End With
I know C# can do it when creating a new object:
Object myObject = new Object { property1 = something, property2 = something2, ...};
But how do I do that if myOject is already created (like what Visual Basic is doing)?
You cannot do this in C#.
This feature is specific to VB and the closest you can come in C# is the object initializer like you describe.
How about this?
static class Extension
{
public static void With<T>(this T obj, Action<T> a)
{
a(obj);
}
}
class Program
{
class Obj
{
public int Prop1 { get; set; }
public int Prop2 { get; set; }
public int Prop3 { get; set; }
public int Prop4 { get; set; }
}
static void Main(string[] args)
{
var detailedName = new Obj();
detailedName.With(o => {
o.Prop1 = 1;
o.Prop2 = 2;
o.Prop3 = 3;
o.Prop4 = 4;
});
}
}
If you're trying to avoid lots of typing you can give your object a shorter name:
var x = myObject;
x.property1 = something;
x.property2 = something2;
Why doesn't C# have VB.NET's 'with' operator?
Many people, including the C# language designers, believe that 'with' often harms readability, and is more of a curse than a blessing. It is clearer to declare a local variable with a meaningful name, and use that variable to perform multiple operations on a single object, than it is to have a block with a sort of implicit context.
by #Jon Skeet
VB.NET includes some of VB6's design flaws for the sake of backward compatibility. While Javascript has the same design flaw (indeed an even worse one, as its with leads to more ambiguous constructs), most other C-syntax languages don't, so there's no backward-compatibility benefit in adding it to C#.
#Mark Byers answer is good but the variable x will live after properties are set. And you can't use name x again (in same block).
Try this (And object must be reference type in this sample) :
void Main()
{
var myObject1 = new Foo();
var myObject2 = new Hoo();
//elided...
{
var _ = myObject1;
_.MyPropertyA = 2;
_.MyPropertyB = "3";
}
{
var _ = myObject2;
_.MyPropertyX = 5;
_.MyPropertyY = "asd";
}
}
If the "with" expression is a class type, the "With" statement is equivalent to creating a new temporary variable of that type, initialized to the "With" expression, and preceding each leading "." with that variable. If it is a structure type, however, things are more complicated. Consider the code (obviously not the way one would normally write something, but written as it is to make a point:
With MyPoints(N) ' Array of Point
N=SomeNewValue
.X = MyPoints(N).X
.Y = MyPoints(N).Y
End With
The "With" statement effectively latches a reference to MyPoints(N). Even if MyPoints is changed to some other array, or N is changed, the latched reference will still point to the same element of the same array as it did when the With statement was executed. If one declared a local variable P of type Point and grabbed MyPoints(N), and then write to P.X and P.Y, the writes would only hit the local copy P, rather than updating the array. To achieve similar semantics in C#, one would have to either use local variables to hold both MyPoints and N, or else place the contents of the With statement within an anonymous function which has a ref parameter of type Point. To avoid having to create a closure at run-time, the anonymous function should also accept, probably by reference, any local variables it will need from the outer scope.

Categories