IronRuby calling C# Extension Methods - Error - Compatibility in .NET 3.5 - c#

I have written an Extension Method off of DataGridView called HideColumns.
public static class Extensions
{
public static void HideColumns(this DataGridView dataGridView, params string[] columnNames)
{
foreach (string str in columnNames)
{
if (dataGridView.Columns[str] != null)
{
dataGridView.Columns[str].Visible = false;
}
}
}
}
I pass my grid into an IronRuby script as a variable called main_grid
When my script calls
main_grid.HideColumns("FirstName","LastName")
the script blows up with Error in Script
undefined method 'HideColumns' for System.Windows.Forms.DataGridView:System::Windows::Forms::DataGridView
The extension methods seem to work okay from C#. What gives?

FWIW, IronRuby 1.1 (needs .net 4) provides the using_clr_extensions method -- as noted in the release notes this activates all extension methods defined on classes defined in a given namespace, regardless of the assembly they are defined in; assemblies loaded in the future that define extension methods in the activated namespace will automatically appear on the correct types, like this:
load_assembly "System.Core"
using_clr_extensions System::Linq
# ...
products.
where(lambda { |p| p.units_in_stock == 0 }).
each { |x| puts x.product_name }
The release notes also point at a whole set of examples at http://github.com/ironruby/ironruby/blob/master/Languages/Ruby/Samples/Linq/101samples.rb

The extension method is just syntatic sugar, you will need to call it as:
Extensions.HideColumns(main_grid, "FirstName", "LastName")
alternatively create a new class in C# which derives from DataGridView and add the method:
public class DataGridViewExt : DataGridView
{
public void HideColumns(params string[] columnNames)
{
foreach (string str in columnNames)
{
if (this.Columns[str] != null)
{
this.Columns[str].Visible = false;
}
}
}
}
and use this class rather than the System.Windows.Forms class on your form.

Since you mentioned it in the comments to JDunkeryly's answer, here's how you'd extend the grid from the ruby side. Just open the class and add a method (only works from the ruby side).
class System::Windows::Forms::DataGridView
def hide_columns(*columnNames)
column_names.each do |cn|
self.columns[cn].visible = false
end
end
end
As far as the suggestion to use the extension method directly, the params keyword is painful to IronRuby. You need to build a typed array with your arguments and pass it. You can't just wrap your ruby strings in a ruby array. I've pulled this off earlier today in a blog post. But if you have a smoother way to handle that, please let me know.

Related

What is the F# equivalent of C# named arguments?

In the DotNetYaml sample code I'm looking at, there's a C# construct:
var deserializer = new Deserializer(namingConvention: new CamelCaseNamingConvention());
var order = deserializer.Deserialize<Order>(input);
What is the equivalent F# code? I've tried
let deserializer = new Deserializer(namingConvention=new CamelCaseNamingConvention())
deserializer.Deserialize<Meta>(input)
If you have a C# library that defines optional parameters, then you can use the syntax you are using in your question. To quickly show that's the case, I compiled the following C# code as a library:
using System;
namespace Demo {
public class MyClass {
public static void Foo(int first, string second = "foo", string third = "bar") { }
}
}
You can reference this and use it from F# as follows:
open Demo
MyClass.Foo(1, third="hi")
I tried to do this with YamlDotNet which, I guess, is the library that you were using, but I get an error that the Deserializer class does not have namingConvention as an argument, so my guess would be that you are probably using a different version of the library than you are thinking (or perhaps, my guess of what library you're using was wrong...).

C# use DLL functions dynamically

I have two folders, one folder with files and the other one with DLL files, I can not know which or how many DLLs there is inside the DLL files directory (modular use).
Inside every DLL file there is a function that gets FileInfo as parameter.
How could I run all the functions in the DLLs on each file from the files directory?
for example, one of the DLL files:
using System;
using System.IO;
namespace DLLTest
{
public class DLLTestClass
{
public bool DLLTestFunction(FileInfo file)
{
return file.Exists;
}
}
}
Main:
DirectoryInfo filesDir = new DirectoryInfo(path_to_files_Directory);
DirectoryInfo dllsDir = new DirectoryInfo(path_to_dlls_Directory);
foreach(FileInfo file in filesDir.getFiles())
{
//How do I run each one of the dll funtions on each one of the files?
}
Thanks a lot.
C# is static typed language, so if you want to call a specific function from many assemblies, the first step is to define one project with an interface for such a function.
You have to create one project (called ModuleInterface or anything else) with one interface :
public interface IDllTest
{
bool DLLTestFunction(FileInfo file);
}
Then all your Dll projects must have at least one classe which implements this interface :
public class DLLTestClass : IDllTest
{
public bool DLLTestFunction(FileInfo file)
{
return file.Exists;
}
}
Note the implementation of IDllTest above (you have to add a reference to project ModuleInterface).
Finally, in your main project, you have to load all your assemblies from a directory :
DirectoryInfo dllsDir = new DirectoryInfo(path_to_dlls_Directory);
foreach(FileInfo file in dllsDir.getFiles())
{
//Load the assembly
Assembly assembly = Assembly.LoadFile (file.FullName);
//Get class which implements the interface IDllTest
Type modules = assembly.GetTypes ().SingleOrDefault(x => x.GetInterfaces().Contains(typeof(IDllTest)));
//Instanciate
IDllTest module = (IDllTest)Activator.CreateInstance (modules);
//Call DllTestFunction (you have to define anyFileInfo)
module.DLLTestFunction(anyFileInfo);
}
It probably need some adjustments, because i don't have test it !
However I'm sure that it's the steps to follow.
Reference (in french) : http://www.lab.csblo.fr/implementer-un-systeme-de-plugin-framework-net-c/
I hope my English is understandable, feel free to correct me.
Niels proposed a very good solution, with a clear interface. If you don't want to create interface, or if you cann't you could iterate all types and methods to find a known signature:
var definedTypes = Assembly.LoadFile("file").DefinedTypes;
foreach(var t in definedTypes)
{
foreach(var m in t.GetMethods())
{
var parameters = m.GetParameters();
if (parameters.Length ==1 && parameters[0].ParameterType == typeof(FileInfo))
{
var instanse = Activator.CreateInstance(t);
m.Invoke(instanse, new[] { fileInfo });
}
}
}
for this you do need that all classes have a parameterless constructor to instanciate it. As a parameter of Invoke method you give your fileInfo object.
You will have to load the assemblies dynamically find the function in it and call it. All steps are described here

Roslyn scripting with enforced script interface

I have simple IScript interface. And I want enforce that all scripts implement it.
public interface IScript<T>
{
T Execute(object[] args);
}
I want to use Roslyn scripting API to achive this. Something like this is possible with CSScript (see Interface Alignment).
var code = #"
using System;
using My.Namespace.With.IScript;
public class Script : IScript<string>
{
public string Execute()
{
return ""Hello from script!"";
}
}
";
var script = CSharpScript.Create(code, ScriptOptions.Default); // + Load all assemblies and references
script.WithInterface(typeof(IScript<string>)); // I need something like this, to enforce interface
script.Compile();
string result = script.Execute(); // and then execute script
Console.WriteLine(result); // print "Hello from script!"
Type safety is a static thing enforced a compile time (of your application). Creating and running a CSharpScript is done at runtime. So you cannot enforce type safety at runtime.
Maybe CSharpScript is not the right way to go. By using this SO answer,
You can compile a piece of C# code into memory and generate assembly bytes with Roslyn.
You would then change the line
object obj = Activator.CreateInstance(type);
to
IScript<string> obj = Activator.CreateInstance(type) as IScript<string>;
if (obj != null) {
obj.Execute(args);
}

How to achieve `FSharpValue.GetUnionFields` in a C# PCL (Profile 259)

I'm in a C# shared project trying to find the PCL (Profile 259) equivalent for FSharpValue.GetUnionFields.
In object browser via the C# project, I see
namespace Microsoft.FSharp.Reflection
{
[AutoOpen]
[CompilationMapping(SourceConstructFlags.Module)]
public static class FSharpReflectionExtensions
{
public static Tuple<UnionCaseInfo, object[]> FSharpValue.GetUnionFields.Static(object value, Type unionType, [OptionalArgument] FSharpOption<bool> allowAccessToPrivateRepresentation);
}
}
This appears to be what I'm looking for, but I'm unable (or don't know how) to call it from C#. Via F#, if I open the namespace, I can call the extension FSharpValue.GetUnionFields. FSharpValue.GetUnionFields does not compile from a c# PCL. I'm not experienced with F# so it could be I'm just lacking some important piece of knowledge related to F# - C# interop?
For reference, this is what I see from a F# pcl.
[<AutoOpen>]
module Microsoft.FSharp.Reflection.FSharpReflectionExtensions
open Microsoft.FSharp.Reflection
val GetUnionFields : value:obj * unionType:System.Type * ?allowAccessToPrivateRepresentation:bool -> UnionCaseInfo * obj []
Repro project here:
https://github.com/kennethito/StackOverflowReferences/tree/master/FSharpValue-GetUnionFields
Again, this requires using reflection. Since it's a PCL, it's particularly nasty, as the actual version of FSharp.Core loaded at runtime is the one that will matter.
The following should work:
public static Tuple<UnionCaseInfo, object[]> TestIt()
{
var option = new FSharpOption<int>(123);
MethodInfo method;
try
{
// If "4.4.0.0" is loaded at runtime, get directly
var t = typeof(FSharpValue);
method = t.GetRuntimeMethods().First(mi => mi.Name == "GetUnionFields");
}
catch
{
var t = typeof(FSharpReflectionExtensions);
method = t.GetRuntimeMethods().First(mi => mi.Name == "FSharp.Value.GetUnionFields.Static");
}
return (Tuple<UnionCaseInfo, object[]>)method.Invoke(null, new object[] { option, option.GetType(), null });
}
This tries to find the method directly on the type (how it's specified in FSharp.Core 4.4), and falls back to the PCL structure (as an extension method).
The following C# console application shows it working:
static void Main(string[] args)
{
Tuple<UnionCaseInfo, object[]> results = CsharpPortable.Test.TestIt();
var uci = results.Item1;
Console.WriteLine("{0}:", uci.Name);
foreach (var pi in uci.GetFields())
{
Console.WriteLine("Property: {0}", pi.Name);
}
Console.ReadKey();
}

How can I export my c# code logic (if-else-loops) in to text files (e.g XML) and later import it back and run?

I have these requirements coming from client every week for some new logic or verification. For which I have to code new logic (basically some if-else and loops) and launch a new build for him. I want to avoid it by simply coding my logic in visual studio then writing a utility to export it to XML or something and send it to client via e-mail. He just have to place this file in some appropriate folder and the application will behave considering this logic.
Please suggest some solutions. My platform is C# Asp.Net.
Thanks
Using .NET 4.6 and the NuGetPackage Microsoft.CodeAnalysis.Scripting you could implement a scripting engine to run your c# code residing in a textfile without building an assembly.
Install NuGet Package:
Install-Package Microsoft.CodeAnalysis.Scripting.CSharp
Implement TestClass with some basic C#-Code-Content:
class Program
{
static void Main(string[] args)
{
TestScript();
}
private static async void TestScript()
{
// Code snippet: a class with one string-property.
string codeContent = #" using System;
public class ScriptedClass
{
public string HelloWorld { get; set; }
public ScriptedClass()
{
HelloWorld = ""Hello Roslyn!"";
}
}
new ScriptedClass().HelloWorld";
// Instanciate CSharpScriptEngine
var engine = new CSharpScriptEngine();
// Execute code and return string property (HelloWorld)
var scriptingState = await engine.ExecuteAsync(codeContent);
// Print return value from CSharpScript
Console.WriteLine("Returned from CSharpScript: {0}", scriptingState.ReturnValue);
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
}
}
Implement a ScriptingEngine:
internal sealed class CSharpScriptEngine
{
public async Task<ScriptState<object>> ExecuteAsync(string codeContent)
{
// Add references from calling assembly
ScriptOptions options = ScriptOptions.Default.AddReferences(Assembly.GetExecutingAssembly());
// Run codeContent with given options
return await CSharpScript.RunAsync(codeContent, options);
}
}
Read ScriptCode from textfile:
So basically you could read some csharpcode from a textfile of your choice and run them on the fly:
private static async void TestScript()
{
// Read in script file
string codeContent = File.ReadAllText(#"C:\Temp\CSharpScriptTest.cs");
var engine = new CSharpScriptEngine();
// Run script
var scriptingState = await engine.ExecuteAsync(codeContent);
Console.WriteLine("Returned from CSharpScript: {0}", scriptingState.ReturnValue);
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
}
In case you are wondering how all of this works under the hood, Roslyn will create a so called submission from your script code. A submission is an in memory assembly containing the types generated around your script code, which can be identified among the assemblies in the current AppDomain by a ℛ prefix in the name.
The precise implementation details are not important here (though, for example, scriptcs heavily relies on understanding in detail how Roslyn works to provide its extra features), but it's important to know that submissions can be chained together. When they are chained, variables, methods or classes defined in an earlier submission are available to use in subsequent submissions, creating a feature of a C# REPL (read-evaluate-print loop).
C# and Visual Basic - Use Roslyn to Write a Live Code Analyzer for Your API
Hope it helps

Categories

Resources