I'm ICE starter. At http://zeroc.com there is good tutorial on how to create chat. I decided to use the tutorial as base. And first thing I tried to do was writing ChatRoom class in c# instead of given c++ implementation. I tried to do the same in my c# code. ChatRoom implementation in c++:
// C++
class ChatRoomCallbackAdapter { /* ... */ };
typedef IceUtil::Handle<ChatRoomCallbackAdapter> ChatRoomCallbackAdapterPtr;
class ChatRoom : public IceUtil::Shared
{
public:
ChatRoom(bool trace, const Ice::LoggerPtr& logger);
void reserve(const std::string&);
void unreserve(const std::string&);
void join(const std::string&, const ChatRoomCallbackAdapterPtr&);
void leave(const std::string&);
Ice::Long send(const std::string&, const std::string&);
private:
typedef std::map<std::string, ChatRoomCallbackAdapterPtr> ChatRoomCallbackMap;
ChatRoomCallbackMap _members;
std::set<std::string> _reserved;
IceUtil::Mutex _mutex;
const bool _trace;
const Ice::LoggerPtr _logger;
};
Some piece of class-members implementation:
// ...
void ChatRoom::reserve(const string& name)
{
IceUtil::Mutex::Lock sync(_mutex);
if(_reserved.find(name) != _reserved.end() ||
_members.find(name) != _members.end())
{
throw string("The name " + name + " is already in use.");
}
_reserved.insert(name);
}
// ...
I was writng next:
public class ChatRoom : IceUtil
when I encountered an error. I found that IceUtil dll in distribution package isn't COM-visible therefore I can't use it in my c# project.
What can I use instead of c++
IceUtil::Handle<T>
as far as I understand it is a smart pointer.
How can I implement server like the one's given in c#?
Would it be the same in c# (talking about mutexes) comparing to above c++ class:
public class ChatRoom
{
// ...
void Reserve(System.String Name)
{
lock(this)
{
// operations
}
}
}
?
Thanks!
I don't know anything about ICE, but their website lists a .NET implementation - why don't you use that instead of COM if you want to use C#? There's even a section of documentation with an example of a C# server.
C++ does not support reference counted pointers out of the box, that is why C++ API has IceUtil::Handle<> template. C# obviously does not need it. I'd recommend you start learning Ice for C# using C# examples rather than C++. You can find a lot of C# client/server examples in democs folder of demos packages. And, of course, Ice has absolutely nothing to do with COM technology, except that it is kind of a replacement.
Related
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...).
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
I'm not a C++ programmer but rather a "code editor", so I hereby apologize sincerely in advance for the question in general.
For some broadcasting software I am editing a plug-in to give it interoperability between native C/++ and CLR (C#).
The host software: OBS (Open Broadcaster Software) - obsproject.com
The plug-in: CLR Host Plugin - github.com/kc5nra/CLRHostPlugin
What I want to do is exposing functions from OBS to some CLR libraries, the total list of exposible functions can be found here: https://github.com/jp9000/OBS/blob/master/OBSApi/APIInterface.h#L198
Now the plug-in is a proxy between the languages and exposes some of the functionalities named above through API.h/cpp, https://github.com/kc5nra/CLRHostPlugin/blob/master/CLRHostInterop/API.h. What I want to do is adding more functions to API.h to expose them to CLR libraries.
When I add a function in API.h, line 51, it'll give me linker errors.
The API.h change
namespace CLROBS
{
public ref class API
{
public:
void AddSettingsPane(SettingsPane^ settingsPane);
void AddImageSourceFactory(ImageSourceFactory^ imageSourceFactory);
IntPtr API::GetMainWindowHandle();
void Log(System::String^ format, ...array<System::Object^> ^arguments);
System::String^ GetPluginDataPath();
void SetChangedSettings(bool isChanged);
int GetMaxFPS();
void StartStopStream(); // Addition to the original.
};
};
The API.cpp change
#include "OBSApi.h"
#include "API.h"
#include "CLRHostApi.h"
#include "OBSUtils.h"
using namespace System::Runtime::InteropServices;
// Default code......
int API::GetMaxFPS()
{
return ::API->GetMaxFPS();
}
void API::StartStopStream()
{
OBSStartStopStream();
}
The Error
error LNK2022: metadata operation failed (80131187) : Inconsistent method declarations in duplicated types (types: CLROBS.API; methods: StartStopStream): (0x0600006c). <DIR>\CLRHostPlugin\CLRHostInterop\API.obj CLRHost.Interop
error LNK2022: metadata operation failed (80131187) : Inconsistent method declarations in duplicated types (types: CLROBS.API; methods: StartStopStream): (0x0600006c). <DIR>\CLRHostPlugin\CLRHostInterop\AbstractPlugin.obj CLRHost.Interop
error LNK2022: metadata operation failed (801311D6) : Differing number of methods in duplicated types (CLROBS.API): (0x02000008). <DIR>\CLRHostPlugin\CLRHostInterop\API.obj CLRHost.Interop
error LNK2022: metadata operation failed (801311D6) : Differing number of methods in duplicated types (CLROBS.API): (0x02000008). <DIR>\CLRHostPlugin\CLRHostInterop\AbstractPlugin.obj CLRHost.Interop
The in my eye's odd behaviour doesn't occur when using the plain code
namespace CLROBS
{
public ref class API
{
public:
void AddSettingsPane(SettingsPane^ settingsPane);
void AddImageSourceFactory(ImageSourceFactory^ imageSourceFactory);
IntPtr API::GetMainWindowHandle();
void Log(System::String^ format, ...array<System::Object^> ^arguments);
System::String^ GetPluginDataPath();
void SetChangedSettings(bool isChanged);
int GetMaxFPS();
// - commented out - void StartStopStream(); // Addition to the original.
};
};
Edit
Added API.cpp snippet
Even when I comment out OBSStartStopStream(); on API.cpp the error still exist.
/Edit
Please assist.
Regards,
MusicDemon
I usually use C# but have the pleasure to invoke a C method via C++. So I wrote a C++ wrapper like this:
The C++ header file looks like this:
#pragma once
using namespace System;
namespace CSharpToCPP {
public ref class SomeWrapper
{
public:
double ReturnValue();
};
}
The C++ code looks like this:
double CSharpToCPP::SomeWrapper::ReturnValue()
{
return 1;
}
This gives me dll which I can reference in C#. The working code in C# looks like this:
class Program
{
static void Main(string[] args)
{
SomeWrapper Wrapper = new SomeWrapper();
Console.WriteLine(Wrapper.ReturnValue());
}
}
Now I would like to create some data in the C++ method ReturnValue and invoke the C method with this signature:
real_T get_value(const e_struct_T parameters, real_T temp)
Can someone please be so kind and point me in the right direction which explains what a const e_struct_T is and how to create such data? The C code was automatically generated and should take a structure with known content. I tried to define a structure in the header file like this:
struct Parameters{
double x;
int y;
char z1;
bool z2;
};
and then populate it with data like this:
Parameters Ps;
Ps.x = z2;
Ps.x = 2.0;
before invoking get_value like this:
get_value(Ps, 10.0);
This does not work. Thanks!
You must search for an header file containing the definition of e_struct_t, include in the calling file, and use a variable of that type to pass to get_value;
By the way, if the target method you want to call from C# is pure C, you probably should consider better using P/Invoke ( a tutorial here ) directly instead of create a C++ wrapper. Furthermore by plain P/Invoke you will drastically simplify the deploy ( no additional dll needed )
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.