I have the following code in C#:
public string Temp
{
get { return sTemp; }
set {
sTemp = value;
this.ComputeTemp();
}
}
Is it possible to convert this and use the get and set this way? I know that you cannot declare like so and I need the ":" to declare but when I try to do this:
public:
std::string Temp
{
get { return sTemp; }
set {
sTemp = value;
this.ComputeTemp();
}
The error I receive is on the first "{" stating expected a ';'. Any suggestions on how to fix it?
Are you using C++/CLI? If so this is the property syntax
public:
property std::string Temp {
std::string get() { return sTemp; }
void set(std::string value) { sTemp = value; this->ComputeTemp(); }
}
If you are trying to use normal C++ then you are out of luck. There is no equivalent feature for normal C++ code. You will need to resort to getter and setter methods
public:
std::string GetTemp() const { return sTemp; }
void SetTemp(const std::string& value) {
sTemp = value;
this->ComputeTemp();
}
To copy paste one of my answers from a similar question:
WARNING: This is a tongue-in-cheek response and is terrible!!!
Yes, it's sort of possible :)
template<typename T>
class Property
{
private:
T& _value;
public:
Property(T& value) : _value(value)
{
} // eo ctor
Property<T>& operator = (const T& val)
{
_value = val;
return(*this);
}; // eo -
operator const T&() const
{
return(_value);
}; // eo ()
};
Then declare your class, declaring properties for your members:
class Test
{
private:
std::string m_Test;
public:
Test() : text(m_Test)
{
};
Property<std::string> text;
};
And call C# style!
Test a;
a.text = "blah";
std::string content = a.text;
In Visual C++ you can use __declspec(property), like this:
public:
__declspec(property(get=get_Temp, put=set_Temp)) std::string Temp;
const std::string& get_Temp { return sTemp; }
void set_Temp(std::string value) {
sTemp = std::move(value);
this->ComputeTemp();
}
Related
In C# how do I write a function that may or may not return a ref to a struct?
What I basically want is a return type Nullable<ref OutboxSlot> but the compiler complains about ref beeing an unexpected token.
I want to do is something like this:
Nullable<ref SomeFieldStruct> GetCorrectField(ref SomeStruct s) {
// Depending on some property of s either return null or a ref to a field of s
}
In something like Rust I could easily declare a return type like Option<&mut SomeFieldStruct>.
PS: No I cannot use classes.
In project properties, in Compilation, you must check "Allow unsafe code":
Don't forget set in Debug and Release.
I'm going to use this structs:
public struct SomeStruct
{
public int Value;
public SomeFieldStruct Field;
}
public struct SomeFieldStruct
{
public double Value;
}
Then, create your method:
public unsafe static SomeFieldStruct* GetCorrectField(ref SomeStruct s)
{
// Depending on some property of s either return null or a ref to a field of s
if (s.Value == 0)
{
fixed (SomeFieldStruct* field = &s.Field)
{
return field;
}
}
return null;
}
If Value is zero, you return the address of Field property of your struct. Check it:
public unsafe static void Test()
{
SomeStruct obj;
obj.Value = 0;
obj.Field.Value = 1.2;
SomeFieldStruct* field = GetCorrectField(ref obj);
if (field != null)
{
field->Value *= 10.0;
}
}
With pointers, you must use arrow -> instead of dot. All your unsafe methods must include unsafe keyword.
I am wrapping some C++ code in managed C++ to access it in C#: I can not figure out how to make operators properly work in C#
I create in managed C++:
public ref class ClassCLI
{
public:
double val;
ClassCLI() {};
void operator ++() { val++; };
double% operator[](int i) { return val; }
};
This works in managed C++:
ClassCLI^ obj = gcnew ClassCLI();
obj++;
obj[0] = 12.0;
But in C#, I can not use the operators ++ or [] directly, I have to use some ugly name that defeats the purpose of operators.
var obj = new ClassCLI();
obj.op_Increment();
obj.op_Subscript(0) = 12.0;
Can one tell me what I am doing wrong ? I says on some posts that operators should be static for C#, it is easy for operator++ but not sure how to do for the operator[]
If you refer to
C++/CLI: how to overload an operator to accept reference types?
How to declare the default indexed property in C++/CLI interface
you can get an idea to implement your ClassCLI class.
Sample implementation:
C++
public ref class ClassCLI
{
public:
double val;
ClassCLI() {};
property double default[int]
{
double get(int index) { return val; }
void set(int index, double value) { val = value; }
}
static ClassCLI^ operator ++(ClassCLI^ c)
{
c->val++;
return c;
};
};
C#:
static void Main()
{
ClassCLI c = new ClassCLI();
Console.WriteLine(c.val);
c++;
Console.WriteLine(c.val);
c[0] = 12;
Console.WriteLine(c.val);
Console.Read();
}
Output:
0
1
12
I need to write this code in C#. Any help would be appreciated.
The interface and the first class is where the issues are. How can I convert that into C#? EnumByteConverter & EnumByteConverter>?
Is this even possible? What would my options be?
public interface EnumByteConverter<E extends Enum<E> & EnumByteConverter<E>>
{
byte convert();
E convert(byte val);
}
public class ReverseByteEnumMap<V extends Enum<V> & EnumByteConverter>
{
private Map<Byte, V> map = new HashMap<>();
public ReverseByteEnumMap(Class<V> valueType)
{
for (V v : valueType.getEnumConstants())
{
map.put(v.convert(), v);
}
}
public V get(byte num)
{
return map.get(num);
}
}
public enum Transport implements EnumByteConverter<Transport>
{
FrameFormatB(0),
FrameFormatA(1),
FrameDraft(254),
FrameUnknown(255);
private static ReverseByteEnumMap<Transport> map = new ReverseByteEnumMap<>(Transport.class);
private final byte value;
Transport(int value)
{
this.value = (byte) value;
}
public byte convert()
{
return value;
}
public Transport convert(byte val)
{
return map.get(val);
}
public static Transport get(byte val)
{
return map.get(val);
}
}
This is what I have tried. I managed to implement the interface using struct, and the reverse class with similar thing.
public interface IEnumByteConverter<E> where E : struct
{
byte Convert();
E Convert(byte val);
}
}
public class ReverseByteEnumMap<T> where T : struct, IEnumByteConverter<T>
{
private Dictionary<Byte, T> map = new Dictionary<Byte, T>();
private IEnumByteConverter<T> converter;
public ReverseByteEnumMap(T valueType)
{
foreach (T t in Enum.GetValues(typeof(T)))
map.Add(t.Convert() , t);
}
public T Get(byte num)
{
return map[num];
}
}
public class Transport : IEnumByteConverter<TransportEnums>
{
public enum TransportEnums
{
FrameFormatB = 0,
FrameFormatA = 1,
FrameDraft = 254,
FrameUnknown = 255
}
private static ReverseByteEnumMap<Transport> map = new ReverseByteEnumMap<Transport> ();
private byte value;
Transport(int value)
{
this.value = (byte)value;
}
public byte Convert()
{
return value;
}
public TransportEnums Convert(byte val)
{
return map.Get(val);
}
public static TransportEnums Get(byte val)
{
return map.Get(val);
}
}
But I got stuck in the last class. I cannot use the Transport.class nor enums. I cannot tell if this a right path I am heading on
In C# it is (quite) easy to change the base type of an enum:
public enum Transport : byte
{
FrameFormatB = 0,
FrameFormatA = 1,
FrameDraft = 254,
FrameUnknown = 255
}
and it is quite easy to convert from the enum to the base type and back:
Transport t1 = (Transport)255; // Equivalent to = Transport.FrameUnknown
int i1 = (int)t1; // 255
byte b1 = (byte)t1; // 255
So you don't need all the support code that you wrote.
In Java enum are classes that don't normally have a "value", and if you want to give them a numerical value you have to do like what is written in your code: define a value field. Then you have to add methods to go from the enum "name" to its "value" and back.
The main problem here is that the C# (.NET) enum can in truth have any value, not only the defined ones:
Transport t2 = (Transport)100;
while in Java only the defined values of enum are legal (because they are the only instances of the enum class that are defined. Other instances can't be created). See for example https://stackoverflow.com/a/469315/613130 .
The code you wrote is quite similar to this one: http://dan.clarke.name/2011/07/enum-in-java-with-int-conversion/
I am facing an issue in SWIG.
As explained in the doc here, SWIG does not support downcasts in Java and C#. I followed the advices of the doc, and create the correct typemaps for the factory of objects. I can know create an object A and downcast it to B.
However, I also have a method returning a vector of pointers to object A. I wrote some typemaps in order to use the factory I made. But then, I can't downcast any element of the vector.
Here is an example:
class A { public:
string name;
void someMethod();
... }
class B : public A {
specialBMethod();
... }
class C : public A {
specialCMethod();
... }
std::vector<std::shared_ptr<A>> someRandomMethod();
And now, I want to this in C# like:
A tmp = someFactoryMethod("B") // will return a B class;
(B)tmp.specialBMethod(); // works fine;
A_vector test = someRandomMethod();
if (test[0].name == "B")
(B)tmp.specialBMethod(); // InvalidCastException
The funniest part, is that if I make a copy of the vector, using CopyTo, and put it in an array for example, it works.
A_vector tmp = someRandomMethod();
A[] test = tmp.ToArray(); // imagine the ToArray method was implemented
if (test[0].name == "B")
(B)tmp.specialBMethod(); // works fine
I think there is a problem when the vector return a const reference of the object. It losts the inheritance and becomes impossible to downcast.
I am pretty lost in this situation. I also opened an issue on the SWIG repo.
Any help would be great;
EDIT : as Flexo asked for, here a minimal, complete example.
example.hpp
class A {
string name;
public:
void someMethod();
string getName() { return name; }
... }
class B : public A {
specialBMethod();
... }
class C : public A {
specialCMethod();
... }
std::vector<std::shared_ptr<A>> someRandomMethod();
example.i
%{
#include "example.hpp"
%}
%pragma(csharp) imclasscode=%{
public static System.Collections.Generic.Dictionary<string, System.Type> aDictionary;
public static System.Collections.Generic.Dictionary<string, System.Type> createDictionary<T>() where T : class
{
System.Collections.Generic.Dictionary<string, System.Type> dictionary = new System.Collections.Generic.Dictionary<string, System.Type>();
foreach (System.Type type in
System.Reflection.Assembly.GetAssembly(typeof(T)).GetTypes())
{
if (type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(T)))
{
string tmp = type.ToString().Split('.')[type.ToString().Split('.').Length - 1].Substring(0, type.ToString().Split('.')[type.ToString().Split('.').Length - 1].IndexOf(typeof(T).Name));
dictionary.Add(tmp, type);
}
}
return dictionary;
}
public static A createA(System.IntPtr cPtr, bool owner)
{
A ret = null;
if (cPtr == System.IntPtr.Zero) {
return ret;
}
string ct = ($imclassname.A_getName(new System.Runtime.InteropServices.HandleRef(null, cPtr)));
if (aDictionary == null)
aDictionary = createDictionary<A>();
if (aDictionary.ContainsKey(ct))
{
System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.CreateInstance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
ret = (A)System.Activator.CreateInstance(aDictionary[ct], flags, null, new object[] { cPtr, owner }, null);
}
else
{
ret = new A(cPtr, owner);
}
return ret;
}
%}
%typemap(csout, excode=SWIGEXCODE)
A*, std::shared_ptr<A> {
System.IntPtr cPtr = $imcall;
Chip ret = liblogicalaccess_examplePINVOKE.createA(cPtr, $owner);$excode
return ret;
}
%include "example.hpp"
test.cs
A tmp = someFactoryMethod("B") // will return a B class;
(B)tmp.specialBMethod(); // works fine;
A_vector test = someRandomMethod();
if (test[0].name == "B")
(B)tmp.specialBMethod(); // InvalidCastException
A_vector tmp = someRandomMethod();
A[] test = new A[tmp.Count];
tmp.CopyTo(test);
if (test[0].name == "B")
(B)tmp.specialBMethod(); // works fine
Edit: As the question has changed, my answer doesn't longer contribute anything.
Try a vector of std::unique_ptr as objects aren't polymorphic.
THE SOLUTION:
https://github.com/swig/swig/issues/1007
I found the answer on the SWIG issues list. It seems I simply forgot a typemap... Because the getitem method from the std::vector wrapping to C# return a reference to T, so I needed to add :
%typemap(csout, excode=SWIGEXCODE)
std::shared_ptr<A>&, // <- ANSWER HERE
A*, std::shared_ptr<A> {
System.IntPtr cPtr = $imcall;
Chip ret = liblogicalaccess_examplePINVOKE.createA(cPtr, $owner);$excode
return ret;
}
I want to have a string, which I then want to pass to 2 variables.
One is Int, the other is string.
So normally I could do:
string1 = string2;
int1 = Convert.ToInt32(string2);
But I wonder if it's possible to do it in another approach,
I want to convert the string to Int just as it reaches the int1 variable; O don't want to convert the actually string2 to Int.
So basically like the topic says:
string1 = int1(convert to int) = string2
I am not sure if this is possible at all, hopefully it is.
Magic.
MagicInt x = 123;
string s = x;
int i = x;
Console.WriteLine("s is " + s);
Console.WriteLine("i is " + i);
public struct MagicInt
{
public MagicInt(int value)
{
_value = value;
}
public MagicInt(string value)
{
_value = int.Parse(value);
}
int _value;
public static implicit operator int(MagicInt value)
{
return value._value;
}
public static implicit operator string(MagicInt value)
{
return value._value.ToString();
}
public static implicit operator MagicInt(int value)
{
return new MagicInt(value);
}
public static implicit operator MagicInt(string value)
{
return new MagicInt(value);
}
}