PythonNET: C# function does not modify class instanced passed to it - c#

I have a C# class like
public MY_CLASS(int number)
{
SomeField = number;
SetElseWhere = 0;
}
}
that I want to pass to a C# function like
public static bool MyTask(string pathXML, out MY_CLASS test)
I expect MyTask to modify the field SetElseWhere in an instance of MY_CLASS
In PythonNet I call the function like
import System
my_dll = System.Reflection.Assembly.LoadFile('example.dll')
MY_CLASS_t = my_dll.GetType('NAMESPACE.MY_CLASS')
my_instance = System.Activator.CreateInstance(MY_CLASS_t)
x = MyTask('test.xml', my_instance)
Now it is getting strange, at least to me:
The returned value x is a tuple with two entries, a boolan and an object
of type NAMESPACE.MY_CLASS. But it is not the instance that I sent in as second parameter stated with property out.
When I check the results I can see that the object in the returned
tuple has been modified correctly, but the instance I send in
has not been modified.
Any ideas why?

Ok, I finally understood your problem and this issue is not documented. There is no concept of out/ref arguments in Python, hence the modifications to arguments are returned in the tuple.
Here is an open issue about this:
https://github.com/pythonnet/pythonnet/issues/228

Related

How to execute static methods by name

I have an XML file with classes name like this:
<ActiveMonitorsList>
<MonitorName>CertificatesMonitor</MonitorName>
<MonitorName>ServicesMonitor</MonitorName>
<MonitorName>LogsMonitor</MonitorName>
<MonitorName>DBMonitor</MonitorName>
</ActiveMonitorsList>
Each of this classes containts a method: bool SingleCheck();
I would like to execute this bool SingleCheck() method for each class that is in this XML file.
What is the best way to do this?
This is what I have so far - it doesn't work:
foreach (string monitorName in monitorsList)
{
Type thisType = GetType();
MethodInfo singleMonitorMethod = thisType.GetMethod("{monitorName}.SingleCheck");
bool methodResult = singleMonitorMethod.Invoke(...);
}
In place of (...) - don't know what to put here, but I want to get
the result of the method (it's always bool).
All of those methods I want to pass as paramters are static.
I guess delegates, Actions or Func<> have to go in here...
Thank You very much in advance!
Edit: Each name in XML points to a separate class. Each class have the same named method: public static bool SingleCheck().
What I want to do is:
get all the monitors names (classes names will be the same)
invoke a method (it has the same name in each class) inside EVERY
class present on that list.
EDIT - PROBLEM SOLVED:
When I first created my project, I included separate folder for all monitors. Then I changed my mind, deleted this folder and added manually SAME FILES to my solution. In this way - those files still had "using <namespace>.Monitors"...
And that's why I couldn't list those classes and the Types were still nulls...
Thanks for all suggestions ! ;)
I would suggest to take this overload of the method Invoke It wants an object(calling instance) and a set of input parameters for the method from you.
Since it is a static method, you can calmly pass null as the first parameter and because you method does not have any parameters you again can calmly pass null as the second value. Don't forget to cast object to the corresponding return type. In your case bool.
bool methodResult = (bool)singleMonitorMethod.Invoke(null, null);
To get the correct Type you actually need to know the namespace! So this would look like this:
foreach (string monitorName in monitorsList)
{
string typeName = $"{yourNameSpace}.{monitorName}";
Type thisType = Type.GetType(typeName);
MethodInfo singleMonitorMethod = thisType.GetMethod("SingleCheck");
bool methodResult = (bool)singleMonitorMethod.Invoke(null, null);
}
If the loop is in the same namespace this should also work:
Type thisType = Type.GetType($"{GetType().Namespace}.{monitorName}");
thisType.GetMethod("{monitorName}.SingleCheck") won't work because of two reasons. 1) You forgot the string interpolation $-sign and thus are searching for a method called "{monitorName}.SingleCheck" which obviously can't exist with such a name. 2) Instead of thisType you need to provide the type containing the method.
Invoke needs to be called with the instance as first parameter - null for static methods - and an object array for the method parameters.
Assuming that your monitor classes are in the same assembly like your current type you would need to do the following:
foreach (string monitorName in monitorsList)
{
Type monitorType = GetType().Assembly.GetExportedTypes().Single(x => x.Name == monitorName);
MethodInfo singleMonitorMethod = monitorType.GetMethod("SingleCheck");
bool methodResult = (bool)singleMonitorMethod.Invoke(null, Array.Empty<object>());
}
I prefer Array.Empty over new object[0] or new object[] { } because it doesn't create a new object every time.
Edited: Changed the type discovery according to Mong Zhu's comment that GetType(monitorName) does need the fully-qualified name.

generate predictable unique string based on a generic objects content

Story
I'm trying to write a generic method which combines property names, types and content value to generate a unique string for the value held by the object passed.
The idea is to generate a unique SHA3-512 Hash based on the generated string sequence which can be used to compare objects on generic bases by looking at their content.
Example
Let's say we have a class like this ...
class MyClass {
private Int32 Id = 5;
public String Name = "some string";
protected DateTime CreateDate = DateTime.Parse("2017-08-21 15:00:07");
}
... and the mentioned method to generate the unique string
static String GetContentString<T>(T obj) where T : class {
...
}
In theory this should work somewhat like this:
var myObj = new MyClass();
var uniqueContentString = GetContentString(myObj);
Console.WriteLine(uniqueContentString);
>>> Id:Int32:5$Name:String:some string$CreateDate:DateTime:2017-08-21 15:00:07
Problem
I'm having difficulties building the GetContentString Method. This is what I have already:
Object obj = ... // given object
Type type = obj.GetType();
IList<PropertyInfo> propertyInfos = type.GetProperties().Where(x => x.CanRead).ToList(); // Marker #2
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo pi in propertyInfos)
{
sb.Append(pi.Name);
sb.Append(":");
sb.Append(pi.PropertyType.Name);
sb.Append(":");
sb.Append(pi.GetValue(obj) ?? "[ISNULL]"); // Marker #1
sb.Append(":");
}
return sb.ToString();
I tried running the method for a few different types of values like "some string" or 1234 (Int32) and ran into a few issues.
Given a string, the method call throws an exception of type System.Reflection.TargetParameterCountException and the message Parameter count mismatch at #1. I found out that an optional index can be passed to an overloaded version of pi.GetValue(..) which then returns one of the single letters. But how do you know when to stop? If you call an index which doesn't exist it throwns an exception of the type System.Reflection.TargetInvocationException. How do you get the value of a string object using reflection?
Given an integer value, the method call doesn't find any properties at #2. Which brings up the question of how to get the value of an integer object using reflection?
And also some general questions; do you guys think this is a good approach to get a unique string? Is reflection the way to go here? Is it even possible to write a generic solution to this problem?
Without looking at reflection, how about JSON serialization with something that .net framework is able to ?
Reflection isn't something extremely fast and you'll run into issues at the first unhandled exception.
Then, you should do that recursivly if your objects can contains complex properties, wich is not a problem with json serialization !

Explanation on this code with delegates

I read quite some articles about delegates, and yes, at first the syntax is confusing. I found this article the most useful. Example 2 makes it quite understandable how to use delegates. But I have this code given to me and have work with it:
public delegate bool IntPredicate(int x);
public delegate void IntAction(int x);
class IntList : List<int>
{
public IntList(params int[] elements) : base(elements)
{
}
public void Act(IntAction f)
{
foreach (int i in this)
{
f(i);
}
}
public IntList Filter(IntPredicate p)
{
IntList res = new IntList();
foreach (int i in this)
if (p(i))
res.Add(i);
return res;
}
}
Now, what confuses me here is the f and p variables in the Act and Filter functions. As in the tutorial, those functions seem to be normal, with normal type of their attributes, but here the attributes are of the delegate functions type and I get confusled.
Can you please enlighten me a bit on this matter?
A delegate is just a type. With the types you're used to (like int, string etc.), when you want to use them, you either use one that is in the framework or you declare your own. You can do exactly the same with delegates - either use a prebuilt one (like System.Action) or declare your own, which is what was done here.
So, in your code snippet, 3 types are declared:
public delegate bool IntPredicate(int x);
public delegate void IntAction(int x);
class IntList : List<int> { ... }
You'll notice that the delegate declarations are on the same level as the class declaration.
When you have a type (like your IntPredicate here), you can then use it for variables or function parameters. The questions now are: how do you set the value of the variable, and what do you do with it then?
With ordinary variables, you just pass in the value. Like this:
string text = "Hello world";
The principle is the same with delegates, but, of course, you have to pass in something that is of the delegate type or something that can be converted to it. You have several options:
Existing method
You can pass in a method, if its signature (that is, the return value and parameters) match those of the delegate. So, you could do this:
void WriteIntAction(int value)
{
Console.WriteLine(value);
}
/* then, in some other method */
IntList intList = new IntList(1,2,3);
intList.Act(WriteIntAction);
Anonymous method
There are several ways to create an anonymous method. I'm going to go with lambda expression, because that is simplest. If you've ever worked with any functional languages, this should be familiar.
IntList intList = new IntList(1,2,3);
intList.Act(x => Console.WriteLine(x));
So, after you have your variable set up with the method you need (whether existing or anonymous), you can simply use the delegate variable as you would any method. This is what this line does:
f(i);
Just be aware that delegate is a reference type, so the value of f here can be null, which will then throw an exception when you try to call a delegate.
TL;DR
A delegate is a type. You can use it in a variable or method parameter. You can pass a method in just using its name or you can create an anonymous method. You can then call the method you passed it by using the variable as you would a method.
You can read more online, for example here: http://msdn.microsoft.com/en-us/library/ms173171.aspx
A delegate type is, for all intents and purposes, just a function (or if you are a C++ user, akin to a function-pointer). In other words, you call them just as if they were a function, which is exactly what the sample code does.
f(i) calls the passed function with the i variable as its sole argument, just as it looks.

How to display the return value from a non static method in C#

I am working with a non static class and want to display the answer of the method to the console window.
When I change the method to static and call from Main() an error stating "Object reference not set to an instance of an object" appears.
http://msdn.microsoft.com/query/dev12.query?appId=Dev12IDEF1&l=EN-US&k=k(EHNullReference);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&rd=true
Why can't you call a non-static method from a static method?
According to this article I need to create an instance of the object using the "new" keyword. My understanding is that you have to create an object for a class and not a method.
http://msdn.microsoft.com/en-us/library/ms173110.aspx
So, I created a new object but it does not return the result.
GetSingleAsset Foo = new GetSingleAsset();
Console.WriteLine(Foo);
The output just gives the name of the method.
How can I see the return value of this non static method?
public Asset GetSingleAsset()
{
var memberId = Oid.FromToken("Member:20", _context.MetaModel);
var query = new Query(memberId);
var nameAttribute = _context.MetaModel.GetAttributeDefinition("Member.Name");
var emailAttribute = _context.MetaModel.GetAttributeDefinition("Member.Email");
query.Selection.Add(nameAttribute);
query.Selection.Add(emailAttribute);
var result = _context.Services.Retrieve(query);
var member = result.Assets[0];
LogResult(member.Oid.Token,
GetValue(member.GetAttribute(nameAttribute).Value),
GetValue(member.GetAttribute(emailAttribute).Value));
return member;
}
You need to do this:
NameOfYourClass instanceOfClass = new NameOfYourClass();
Console.WriteLine(instanceOfClass.NameOfMethod());
The "answer of the method to the console window" - in this case, is an object - and if you attempt to Console.WriteLine() an object, you will only see the object type written out to the Console - not its values.
Yes, Robert is correct - GetSingleAsset() is a method, not a class - because it returns a value of 'Asset' type - a class's constructor will have no return - and Patrick is correct if you want to see (via Console output) what the return is from that particular method - if it wasn't an object.
However, since 'Asset' is an object itself, if you simply did a Console.WriteLine(Asset) it would show you what the type of Asset deviates from .. not its values. For example, "System.Collection.Asset" would be printed and not the values that you are interested in.
You will need to put a breakpoint in the code at the point of class instantiation and look through the Locals Window to see the values that type 'Asset' contains and print out exactly the values that you are interested in ... chances are what values you are actually interested in are contained within another object within the Asset class .. perhaps a for loop is in order here.

Ambiguous call of method

I have the following code
class Program
{
static void Main()
{
A a = new A();
a.M(null);
}
}
class A
{
public void M(int? i)
{ }
public void M(string s)
{ }
}
And I have an error, because the call is ambiguous. I need to change the call of M method without adding any lines to Main method and accessing class A so that it became correct. Could someone please tell me how to do this?
You can use explicit cast:
A a = new A();
a.M((string)null);
or
a.M((int?)null);
to help the compiler of picking the right overload. Note that C# compiler can't determine what method overload to call based on null literal.
For advanced topic consider Eric's article What is the type of the null literal?
edit:
since your argument names are different, you can use named arguments, which are avaliable since C# 4.0:
a.M(i : null);
or
a.M(s : null);
You can use a cast, or the default keyword, or for int?, new int?() (which, due to how Nullable types work, is also the same as null). You could also use named parameters to disambiguate. Or, of course, if you were ok with adding another line, you could declare your value in a variable and pass that in.
// these call the int? overload
a.M(default(int?));
a.M((int?)null);
a.M(new int?());
a.M(i: null);
int? i = null;
a.M(i);
// these call the string overload
a.M(default(string));
a.M((string)null);
a.M(s: null);
string s = null;
a.M(s);
The answer is that you cannot overload the member M this way if you cannot alter existing call sites.
Presumably you are adding one of the two methods and can alter the call sites for calls to the new method. Change the name of the method for those new call sites to use.

Categories