Does anyone have a working, step-by-step example of how to implement IEnumerable and IEnumerator in C++/CLI? Alternatively, does someone know how to fix the following code from MS Connect which does not compile in Visual Studio 2005?
http://connect.microsoft.com/VisualStudio/feedback/details/101089/how-to-implement-ienumerable-t-and-ienumerable-c-cli
using namespace System;
using namespace System::Collections::Generic;
generic <class T>
public ref struct MyArray : public IEnumerable<T>
{
MyArray( array<T>^ d )
{
data = d;
}
ref struct enumerator : IEnumerator<T>
{
enumerator( MyArray^ myArr )
{
colInst = myArr;
currentIndex = -1;
}
bool MoveNext()
{
if( currentIndex < colInst->data->Length - 1 )
{
currentIndex++;
return true;
}
return false;
}
property T Current
{
T get()
{
return colInst->data[currentIndex];
}
};
// This is required as IEnumerator<T> also implements IEnumerator
property Object^ Current2
{
virtual Object^ get() new sealed = System::Collections::IEnumerator::Current::get
{
return colInst->data[currentIndex];
}
};
void Reset() {}
~enumerator() {}
MyArray^ colInst;
int currentIndex;
};
array<T>^ data;
IEnumerator<T>^ GetEnumerator()
{
return gcnew enumerator(this);
}
virtual System::Collections::IEnumerator^ GetEnumerator2() new sealed = System::Collections::IEnumerable::GetEnumerator
{
return gcnew enumerator(this);
}
};
int main()
{
int retval = 0;
MyArray<int>^ col = gcnew MyArray<int>( gcnew array<int>{10, 20, 30 } );
for each( Object^ c in col )
{
retval += (int)c;
}
retval -= 10 + 20 + 30;
Console::WriteLine("Return Code: {0}", retval );
return retval;
}
The compiler is unable to find the enumerator method implementations:
error C3766: 'MyArray<T>::enumerator' must provide an implementation for the interface method 'bool System::Collections::IEnumerator::MoveNext(void)' c:\Projects\VCNET\2005\IEnumerable\IEnumerable\IEnumerable.cpp 55
error C3766: 'MyArray<T>::enumerator' must provide an implementation for the interface method 'void System::Collections::IEnumerator::Reset(void)' c:\Projects\VCNET\2005\IEnumerable\IEnumerable\IEnumerable.cpp 55
error C3766: 'MyArray<T>::enumerator' must provide an implementation for the interface method 'T System::Collections::Generic::IEnumerator<T>::Current::get(void)' c:\Projects\VCNET\2005\IEnumerable\IEnumerable\IEnumerable.cpp 55
error C3766: 'MyArray<T>' must provide an implementation for the interface method 'System::Collections::Generic::IEnumerator<T> ^System::Collections::Generic::IEnumerable<T>::GetEnumerator(void)' c:\Projects\VCNET\2005\IEnumerable\IEnumerable\IEnumerable.cpp 68
This compiles for me without a single warning (on VS2010):
using namespace System;
using namespace System::Collections::Generic;
generic <class T>
public ref struct MyArray : public IEnumerable<T>
{
MyArray( array<T>^ d )
{
data = d;
}
ref struct enumerator : IEnumerator<T>
{
enumerator( MyArray^ myArr )
{
colInst = myArr;
currentIndex = -1;
}
virtual bool MoveNext() = IEnumerator<T>::MoveNext
{
if( currentIndex < colInst->data->Length - 1 )
{
currentIndex++;
return true;
}
return false;
}
property T Current
{
virtual T get() = IEnumerator<T>::Current::get
{
return colInst->data[currentIndex];
}
};
// This is required as IEnumerator<T> also implements IEnumerator
property Object^ Current2
{
virtual Object^ get() = System::Collections::IEnumerator::Current::get
{
return colInst->data[currentIndex];
}
};
virtual void Reset() = IEnumerator<T>::Reset {}
~enumerator() {}
MyArray^ colInst;
int currentIndex;
};
array<T>^ data;
virtual IEnumerator<T>^ GetEnumerator()
{
return gcnew enumerator(this);
}
virtual System::Collections::IEnumerator^ GetEnumerator2() = System::Collections::IEnumerable::GetEnumerator
{
return gcnew enumerator(this);
}
};
int main()
{
int retval = 0;
MyArray<int>^ col = gcnew MyArray<int>( gcnew array<int>{10, 20, 30 } );
for each( Object^ c in col )
{
retval += (int)c;
}
retval -= 10 + 20 + 30;
Console::WriteLine("Return Code: {0}", retval );
return retval;
}
Related
Hello i am bigginer in programing and i have specific problem.
I have been learning a new ways to write a code in small Arduino project.
that project have multiple objects like distance measuring Senzor, led diods , temperature senzor, etc. And all this objects have its own menu where you can, for example, start a calibration or just get values.
What i need is singleton class that has a function enter_esc() that need a int (*funct)() parameter basically function pointer.
That enter_esc(int (*funct)()) function just looping function until you press escape pin which is defined.
function Calibration() have inside some private: object data types like value or cali_value.
so i tried to insert function Calibration() right into enter_esc(Calibration) but it won't compile becouse i didnt pass that vlaues by reference or copy.
but what i found is lambda.
i made a lamda similar to a Calibration() function and i passed values by reference &{//domething;}
but i had to use enter_esc(std::function<int()>& funct) whitch is only int C++ standard library and not in Arduino C/C++ so my qestion is:
[is there some way how to pass values by reference by using lambda to a singleton class in Arduino ?]
(i konw it can be done differently but like i said i want to learn some new ways to program, also if you have some different way to make it i will by very happy to see it)
10Q for your time :)
//Class.h
#pragma once
class events {
private:
static events e_instance;
int p_menu, p_enter, p_esc, p_up, p_down;
int menuValue;
events();
public:
events(const events&) = delete;
static events& Get();
int ArrowUpDown(int maxVal);
int ArrowUpDown(int p_up, int p_down, int maxVal);
int enter_esc(const std::function<int()>& funct);
};
events events::e_instance;
class deviceBase : public Printables
{
public:
const char* a_pin;
int d_pin;
String type;
String deviceName;
bool inUse;
int actualCount;
public:
String getType() override;
int getActualCount() override;
String getName() override;
String getInUse() override;
};
class senzor : public deviceBase
{
private:
int Value;
int triggValue;
public:
int p_triggValue = 10;
static int allSenzors;
friend events;
senzor();
~senzor();
public:
int getValue();
int Calibration();
void changeTriggVal(int x);
void Reset();
void nullCalibration();
void Menu(int x);
void setName(String deviceName);
void setInUse(bool x);
int getPin();
};
int senzor::allSenzors = 0;
if you have some good advice to my code writing i will be also very glad
//Class.cpp
#include <iostream>
#include <string>
#include <functional>
#define LOG(x) std::cout << x << std::endl;
#define PINMENU 12
#define PINENTER 8
#define PINESC 9
#define PINUP 11
#define PINDOWN 13
using String = std::string;
struct Printables
{
virtual String getType() = 0;
virtual int getActualCount() = 0; ;
virtual String getName() = 0;
virtual String getInUse() = 0;
};
#include "Class.h"
events& events::Get() {
return e_instance;
}
int events::ArrowUpDown(int maxVal) {
if (maxVal) {
menuValue = menuValue < maxVal ? menuValue++ : menuValue;
}
if (maxVal) {
menuValue = menuValue > 0 ? menuValue-- : menuValue;
}
return menuValue;
}
int events::enter_esc(const std::function<int()>&funct) {
if (1) {
while (!p_esc) {
auto f = funct;
}
}
return 1;
}
int events::ArrowUpDown(int p_up, int p_down, int maxVal) { return 666; }
events::events() {};
String deviceBase::getType() { return type; }
int deviceBase::getActualCount() { return actualCount; }
String deviceBase::getName() { return deviceName; }
String deviceBase::getInUse() {
String Status;
Status = inUse == 1 ? "Active" : "Deactive";
return Status;
}
senzor::senzor() : Value(0), triggValue(1) {
a_pin = "xx";
type = "[SENZOR]";
deviceName = "[UNKNOWN]";
inUse = 0;
allSenzors++;
actualCount = allSenzors;
a_pin = 0;
}
senzor::~senzor() {
allSenzors = 0;
}
int senzor::getValue() {
Value = 4;
return Value;
}
int senzor::Calibration() {
triggValue = triggValue < getValue() ? getValue() : triggValue;
p_triggValue = triggValue;
return p_triggValue;
}
void senzor::changeTriggVal(int x) {
p_triggValue = x;
}
void senzor::Reset() {
p_triggValue = triggValue;
}
void senzor::nullCalibration() {
triggValue = 1;
}
void senzor::setName(String deviceName) {
this->deviceName = deviceName;
}
void senzor::setInUse(bool x) {
inUse = x;
}
int senzor::getPin() {
return 4;
}
int printsss() {
return 1;
}
////////////////////////////////this what i was writing about//////////////////////////////
void senzor::Menu(int x) {
events::Get().enter_esc([&]() { triggValue = triggValue < getValue() ? getValue() : triggValue;
p_triggValue = triggValue;
return p_triggValue; });
}
but if i use lambda in arduino with enter_esc(int (*funct)()) i get this kind of error
no matching function for call to 'events::enter_esc(senzor::Menu(int)::<lambda()>)'
I'm trying to aplicate Flyweight method pattern in a simple .net core Api to see how much memory is saved compared to not using the pattern.
I have two methods, the first one creates 5000 objects without uses the pattern and the another creates 5000 object using the pattern. After each of them create the objects, then they call a method that returns the current memory used by the App.
public class MemoryService : IMemoryService
{
private readonly TreeFactory _treeFactory;
public MemoryService()
{
_treeFactory = new TreeFactory();
}
//create without pattern
public long SetObjectsMemory()
{
List<Tree> trees = new List<Tree>();
for (int i = 0; i < 5000; i++)
{
var tree = new Tree()
{
Id = new Random().Next(1, 9999999),
Part = new PartTree()
{
Name = "Nameany",
Bark = "Barkany",
Color = "Colorany"
}
};
trees.Add(tree);
};
return Utilities.GetCurrentMemoryUsed();
}
//crete with flyweight pattern
public long SetObjectsMemoryFactory()
{
List<Tree> trees = new List<Tree>();
for (int i = 0; i < 5000; i++)
{
var tree = new Tree()
{
Id = new Random().Next(1, 9999999),
Part = _treeFactory.GetPartTree("Nameany", "Barkany", "Colorany")
};
trees.Add(tree);
}
return Utilities.GetCurrentMemoryUsed();
}
}
I use the pattern like a class that uses a list of Parts and return a part object if exists.
public class TreeFactory
{
private static List<PartTree> _parts;
public TreeFactory() {
_parts = new List<PartTree>();
}
public PartTree GetPartTree(string name, string bark, string color)
{
if (_parts.Any(x => x.Name == name && x.Bark == bark && x.Color == color))
{
return _parts.Where(x => x.Name == name && x.Bark == bark && x.Color == color).FirstOrDefault();
}
else {
var newpart = new PartTree()
{
Name = name,
Bark = bark,
Color = color
};
_parts.Add(newpart);
return newpart;
}
}
}
The way to get the current memory used by the App is using Process of this way (in Utilities class):
public static long GetCurrentMemoryUsed() {
Int64 memory;
using (Process proc = Process.GetCurrentProcess())
{
memory = proc.PrivateMemorySize64 / (1024 * 1024);
}
return memory;
}
And in my Startup i inject the MemoryService like a Singleton. In the controller i use 3 methods for call the functions:
[HttpGet, Route(nameof(WeatherForecastController.GenerateMemory))]
public IActionResult GenerateMemory()
{
var total=_memoryService.SetObjectsMemory();
return Ok(total);
}
[HttpGet, Route(nameof(WeatherForecastController.GenerateLiftMemory))]
public IActionResult GenerateLiftMemory()
{
var total = _memoryService.SetObjectsMemoryFactory();
return Ok(total);
}
[HttpGet, Route(nameof(WeatherForecastController.GetMemory))]
public IActionResult GetMemory()
{
var total = Utilities.GetCurrentMemoryUsed();
return Ok(total);
}
The problem is: When i call in the navigator the method in controller without pattern (/weatherforecast/GenerateMemory), then this returns (current)+2mb, but when i call the method
with pattern (/weatherforecast/GenerateLiftMemory) this returns (current)+3mb.
Why the method with pattern flyweight returns more used MB (growing) than the methods without the pattern ??
The repository with the code for test it. Gitlab repository memory api
The code which uses TreeFactory consumes more memory because its GetPartTree method called many times in a loop so as Linq methods Any and Where inside it. Both of these methods create additional Iterator objects under the hood in order to iterate through the collection and it causes additional memory consumption.
I wrote simple benchmark using BenchmarkDotNet with more options to demonstrate the issue
Extended MemoryService
public class MemoryService : IMemoryService
{
private const int TreeCount = 50000;
private readonly TreeFactory _treeFactory;
public MemoryService()
{
_treeFactory = new TreeFactory();
}
//crea objetos en memoria sin patrones
public decimal SetObjectsMemory()
{
List<Tree> trees = new List<Tree>();
for (int i = 0; i < TreeCount; i++)
{
var tree = new Tree()
{
Id = 1,
Part = new PartTree()
{
Name = "Nameany",
Bark = "Barkany",
Color = "Colorany"
}
};
trees.Add(tree);
};
return Utilities.GetCurrentMemoryUsed();
}
//crea objetos en memoria usando patron flyweight
public decimal SetObjectsMemoryFactory()
{
List<Tree> trees = new List<Tree>();
for (int i = 0; i < TreeCount; i++)
{
var tree = new Tree()
{
Id = 1,
Part = _treeFactory.GetPartTree("Nameany", "Barkany", "Colorany")
};
trees.Add(tree);
}
return Utilities.GetCurrentMemoryUsed();
}
public decimal SetObjectsMemoryFactoryImproved()
{
List<Tree> trees = new List<Tree>();
for (int i = 0; i < TreeCount; i++)
{
var tree = new Tree()
{
Id = 1,
Part = _treeFactory.GetPartTreeImproved("Nameany", "Barkany", "Colorany")
};
trees.Add(tree);
}
return Utilities.GetCurrentMemoryUsed();
}
//crea objetos en memoria usando patron flyweight
public decimal SetObjectsMemoryFactoryWithoutLambda()
{
List<Tree> trees = new List<Tree>();
for (int i = 0; i < TreeCount; i++)
{
var tree = new Tree()
{
Id = 1,
Part = _treeFactory.GetPartTreeWithoutLambda("Nameany", "Barkany", "Colorany")
};
trees.Add(tree);
}
return Utilities.GetCurrentMemoryUsed();
}
}
Extended TreeFactory
public class TreeFactory
{
private static List<PartTree> _parts;
public TreeFactory()
{
_parts = new List<PartTree>();
}
public PartTree GetPartTree(string name, string bark, string color)
{
if (_parts.Any(x => x.Name == name && x.Bark == bark && x.Color == color))
{
return _parts.Where(x => x.Name == name && x.Bark == bark && x.Color == color).FirstOrDefault();
}
var newpart = new PartTree()
{
Name = name,
Bark = bark,
Color = color
};
_parts.Add(newpart);
return newpart;
}
public PartTree GetPartTreeImproved(string name, string bark, string color)
{
var existingPart = _parts.Where(x => x.Name == name && x.Bark == bark && x.Color == color).FirstOrDefault();
if (existingPart != null)
return existingPart;
var newpart = new PartTree()
{
Name = name,
Bark = bark,
Color = color
};
_parts.Add(newpart);
return newpart;
}
public PartTree GetPartTreeWithoutLambda(string name, string bark, string color)
{
for (int i = 0; i < _parts.Count; i++)
{
var x = _parts[i];
if (x.Name == name && x.Bark == bark && x.Color == color)
return x;
}
var newpart = new PartTree()
{
Name = name,
Bark = bark,
Color = color
};
_parts.Add(newpart);
return newpart;
}
}
Benchmark in a separate console project
class Program
{
static void Main(string[] args)
{
var result = BenchmarkRunner.Run<MemoryBenchmark>();
}
}
[MemoryDiagnoser]
public class MemoryBenchmark
{
private IMemoryService memoryService;
[GlobalSetup]
public void Setup()
{
memoryService = new MemoryService();
}
[Benchmark]
public object SimpleTrees()
{
var trees = memoryService.SetObjectsMemory();
return trees;
}
[Benchmark]
public object FlyTrees()
{
var trees = memoryService.SetObjectsMemoryFactory();
return trees;
}
[Benchmark]
public object FlyTreesImproved()
{
var trees = memoryService.SetObjectsMemoryFactoryImproved();
return trees;
}
[Benchmark]
public object FlyTreesWithoutLambda()
{
var trees = memoryService.SetObjectsMemoryFactoryWithoutLambda();
return trees;
}
}
And its results
Method
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
SimpleTrees
9.040 ms
0.1804 ms
0.2346 ms
718.7500
453.1250
265.6250
4.44 MB
FlyTrees
19.701 ms
0.1716 ms
0.1521 ms
2500.0000
906.2500
437.5000
15.88 MB
FlyTreesImproved
18.075 ms
0.2869 ms
0.2684 ms
1781.2500
625.0000
312.5000
10.92 MB
FlyTreesWithoutLambda
4.919 ms
0.0273 ms
0.0242 ms
421.8750
281.2500
281.2500
2.53 MB
Basically, what is happening is when trying to change a variable of a Managed class (UWP), it crashes. Additionally, it seems to only crash if I try modifying a variable which is created with the app namespace. In other words, if I create a new namspace and managed class, I can modify variables just fine.
void ASynTaskCategories(void)
{
concurrency::task_completion_event<Platform::String^> taskDone;
MainPage^ rootPage = this;
UberSnip::HELPER::ASYNC_RESPONSE^ responseItem = ref new UberSnip::HELPER::ASYNC_RESPONSE();
create_task([taskDone, responseItem, rootPage]() -> Platform::String^
{
//UBERSNIP API 0.4
UberSnip::UBERSNIP_CLIENT* UberSnipAPI = new UberSnip::UBERSNIP_CLIENT();
UberSnipAPI->Http->RequestURL = "http://api.ubersnip.com/categories.php";
UberSnipAPI->Http->request();
taskDone.set(UberSnipAPI->Client->BodyResponse);
responseItem->Body = UberSnipAPI->Client->BodyResponse;
return "(done)";
}).then([taskDone, responseItem, rootPage](Platform::String^ BodyResponse) {
Platform::String^ BR = responseItem->Body;
cJSON* cats = cJSON_Parse(_string(BR));
cats = cats->child;
int *cat_count = new int(cJSON_GetArraySize(cats));
rootPage->Categories->Clear();
GENERIC_ITEM^ all_item = ref new GENERIC_ITEM();
all_item->Title = "All";
rootPage->Categories->Append(all_item);
for (int i = 0; i < *cat_count; i++) {
cJSON* cat = new cJSON();
cat = cJSON_GetArrayItem(cats, i);
string *track_title = new string(cJSON_GetObjectItem(cat, "name")->valuestring);
GENERIC_ITEM gitem;
gitem.Title = "Hi";
GENERIC_ITEM^ ubersnipCategory = ref new GENERIC_ITEM();
ubersnipCategory->Title = _String(*track_title);
rootPage->Categories->Append(ubersnipCategory);
}
});
This does not crash
UberSnipAPI->Http->RequestURL = "http://api.ubersnip.com/categories.php";
but this one does
all_item->Title = "All";
I am almost positive it has something to do with it being in the apps default namespace and it being accessed outside of the main thread ... At least that's what it seems like as that's really the only difference besides the actual class.
This is what GENERIC_ITEM looks like.
[Windows::UI::Xaml::Data::Bindable]
public ref class GENERIC_ITEM sealed {
private:
Platform::String^ _title = "";
Platform::String^ _description;
Windows::UI::Xaml::Media::ImageSource^ _Image;
event PropertyChangedEventHandler^ _PropertyChanged;
void OnPropertyChanged(Platform::String^ propertyName)
{
PropertyChangedEventArgs^ pcea = ref new PropertyChangedEventArgs(propertyName);
_PropertyChanged(this, pcea);
}
public:
GENERIC_ITEM() {
};
property Platform::String^ Title {
Platform::String^ get() {
return this->_title;
}
void set(Platform::String^ val) {
this->_title = val;
OnPropertyChanged("Title");
}
}
property Platform::String^ Description {
Platform::String^ get() {
return this->_description;
}
void set(Platform::String^ val) {
this->_description = val;
OnPropertyChanged("Description");
}
}
void SetImage(Platform::String^ path)
{
Windows::Foundation::Uri^ uri = ref new Windows::Foundation::Uri(path);
_Image = ref new Windows::UI::Xaml::Media::Imaging::BitmapImage(uri);
}
};
I know there is no issue with the class because it works perfectly fine if I run this exact same code on the initial thread.
Any suggestions? Thanks! :D
Figured it out after several hours! In case someone else is having this issue, all you must do is use the Dispatcher to run code on the UI that is not available outside of the UI thread.
void loadCats(UberSnip::HELPER::ASYNC_RESPONSE^ responseItem, MainPage^ rootPage) {
Platform::String^ BR = responseItem->Body;
cJSON* cats = cJSON_Parse(_string(BR));
cats = cats->child;
int *cat_count = new int(cJSON_GetArraySize(cats));
rootPage->Categories->Clear();
GENERIC_ITEM^ all_item = ref new GENERIC_ITEM();
all_item->Title = "All";
rootPage->Categories->Append(all_item);
for (int i = 0; i < *cat_count; i++) {
cJSON* cat = new cJSON();
cat = cJSON_GetArrayItem(cats, i);
string *track_title = new string(cJSON_GetObjectItem(cat, "name")->valuestring);
GENERIC_ITEM gitem;
gitem.Title = "Hi";
GENERIC_ITEM^ ubersnipCategory = ref new GENERIC_ITEM();
ubersnipCategory->Title = _String(*track_title);
rootPage->Categories->Append(ubersnipCategory);
}
}
void ASyncTaskCategories(void)
{
concurrency::task_completion_event<Platform::String^> taskDone;
MainPage^ rootPage = this;
UberSnip::HELPER::ASYNC_RESPONSE^ responseItem = ref new UberSnip::HELPER::ASYNC_RESPONSE();
auto dispatch = CoreWindow::GetForCurrentThread()->Dispatcher;
auto op2 = create_async([taskDone, responseItem, rootPage, dispatch] {
return create_task([taskDone, responseItem, rootPage, dispatch]() -> Platform::String^
{
//UBERSNIP API 0.4
UberSnip::UBERSNIP_CLIENT* UberSnipAPI = new UberSnip::UBERSNIP_CLIENT();
UberSnipAPI->Http->RequestURL = "http://api.ubersnip.com/categories.php";
try{
UberSnipAPI->Http->request();
}
catch (...) {
printf("Error");
}
int err = UberSnip::UTILS::STRING::StringToAscIIChars(UberSnipAPI->Client->BodyResponse).find("__api_err");
if (err < 0) {
if (UberSnip::UTILS::STRING::StringToAscIIChars(UberSnipAPI->Client->BodyResponse).length() < 3) {
return;
}
}
taskDone.set(UberSnipAPI->Client->BodyResponse);
responseItem->Body = UberSnipAPI->Client->BodyResponse;
dispatch->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, ref new Windows::UI::Core::DispatchedHandler([=]()
{
rootPage->loadCats(responseItem, rootPage);
}));
for (int i = 0; i < 100;) {
}
return "(done)";
}).then([taskDone, responseItem, rootPage](Platform::String^ BodyResponse) {
});
});
//rootPage->loadCats(responseItem, rootPage);
}
I had to build my own Version class. In .NET it's CLS Compliant but in Mono its not for some reason. Any ideas why?
[Serializable]
public class Version : ICloneable, IComparable, IComparable<Version>, IEquatable<Version>
{
private int major;
private int minor;
private int revision;
private int build;
protected Version()
{
}
public Version(int major, int minor)
{
Major = major;
Minor = minor;
}
public Version(int major, int minor, int revision, int build) : this(major, minor)
{
Revision = revision;
Build = build;
}
public Version(string version)
{
if (string.IsNullOrWhiteSpace(version))
{
throw new ControlInfluence.Exceptions.ArgumentNullStringException("version");
}
string[] parts = version.Split('.');
if ((parts.Length != 4) && (parts.Length != 2))
{
throw new ArgumentException("'version' must have 2 or 4 numbers separated by '.'.", "version");
}
if (!int.TryParse(parts[0], out major))
{
throw new ArgumentException("'version' must have 2 or 4 numbers separated by '.'.", "version");
}
if (!int.TryParse(parts[1], out minor))
{
throw new ArgumentException("'version' must have 2 or 4 numbers separated by '.'.", "version");
}
if (!int.TryParse(parts[2], out revision))
{
throw new ArgumentException("'version' must have 2 or 4 numbers separated by '.'.", "version");
}
if (!int.TryParse(parts[3], out build))
{
throw new ArgumentException("'version' must have 2 or 4 numbers separated by '.'.", "version");
}
}
public int Major
{
get
{
return major;
}
set
{
major = value;
}
}
public int Minor
{
get
{
return minor;
}
set
{
minor = value;
}
}
public int Build
{
get
{
return build;
}
set
{
build = value;
}
}
public int Revision
{
get
{
return revision;
}
set
{
revision = value;
}
}
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0}.{1}.{2}.{3}", Major, Minor, Revision, Build);
}
public static bool operator <(Version left, Version right)
{
if ((left == null) || (right == null))
{
return false;
}
return left.CompareTo(right) < 0;
}
public static bool operator >(Version left, Version right)
{
if ((left == null) || (right == null))
{
return false;
}
return left.CompareTo(right) > 0;
}
#region ICloneable Members
public object Clone()
{
return new Version(Major, Minor, Revision, Build);
}
#endregion
#region IComparable Members
public int CompareTo(object obj)
{
Version other = obj as Version;
if (other == null)
{
return -1;
}
return CompareTo(other);
}
#endregion
#region IComparable<Version> Members
public int CompareTo(Version other)
{
if (other == null)
{
return -1;
}
int compareMajor = Major.CompareTo(other.Major);
if (compareMajor != 0)
{
return compareMajor;
}
int compareMinor = Minor.CompareTo(other.Minor);
if (compareMinor != 0)
{
return compareMinor;
}
int compareRevision = Revision.CompareTo(other.Revision);
if (compareRevision != 0)
{
return compareRevision;
}
return Build.CompareTo(other.Build);
}
#endregion
#region IEquatable<Version> Members
public bool Equals(Version other)
{
return CompareTo(other) == 0;
}
#endregion
public override bool Equals(object obj)
{
Version version = obj as Version;
if (version == null)
{
return false;
}
return Equals(version);
}
public static bool operator ==(Version left, Version right)
{
if (Object.ReferenceEquals(left, null) && Object.ReferenceEquals(right, null))
{
return true;
}
if (Object.ReferenceEquals(left, null) || Object.ReferenceEquals(right, null))
{
return false;
}
return left.Equals(right);
}
public static bool operator !=(Version left, Version right)
{
if ((left == null) || (right == null))
{
return false;
}
return !left.Equals(right);
}
}
The custom exception classes I throw are simply wrappers around ArgumentNullException that "auto fill" the message for me so they aren't adding any types to it really.
If it's CLS compliant in .NET but not on Mono, it is a bug in Mono. Please file a bug in http://bugzilla.xamarin.com
i would like to assign my array vals to properties of my object.
like:
For i = 1 To 32
myClass.Prop_i = val[i]
Next
VB.NET isn't a dynamic language: you can't do such things.
Since VB.NET doesn't have a "dynamic" keyword like C#, your option is reflection:
myClass.GetType().GetProperty("Prop_" + i.ToString()).SetValue(myClass, val[i], null);
But if you're more explicit with your problem maybe there's a more elegant solution than reflection ;)
Your property needs to define Set. This will allow you to modify the property.
If you are willing to write some code in C# and use it in VB.NET, and need to store primitive types like int, float or byte, and all your properties are of the same type. Then you can create a union structure with an array covering the fields.
Then you can use code like this:
Sub Main() ' vb.net
Dim bag As New PropertyBag()
bag.AllProperties = New Single() {1, 2, 3, 4, 5, 6, 7, 8}
Dim three As Single = bag.Prop_3 'returns 3
Dim five As Single = bag(4) 'returns 5 (0-based index)
End Sub
When declared like
[StructLayout(LayoutKind.Explicit, Size=Size)]
public unsafe struct PropertyBag
{
const int Count = 8; //8 fields
const int Size = 8 * 4; //4 bytes per field
[FieldOffset(0)]
fixed float list[Count];
[FieldOffset(0)] float x1;
[FieldOffset(4)] float x2;
[FieldOffset(8)] float x3;
[FieldOffset(12)] float x4;
[FieldOffset(16)] float x5;
[FieldOffset(20)] float x6;
[FieldOffset(24)] float x7;
[FieldOffset(28)] float x8;
public float Prop_1 { get { return x1; } set { x1 = value; } }
public float Prop_2 { get { return x2; } set { x2 = value; } }
public float Prop_3 { get { return x3; } set { x3 = value; } }
public float Prop_4 { get { return x4; } set { x4 = value; } }
public float Prop_5 { get { return x5; } set { x5 = value; } }
public float Prop_6 { get { return x6; } set { x6 = value; } }
public float Prop_7 { get { return x7; } set { x7 = value; } }
public float Prop_8 { get { return x8; } set { x8 = value; } }
public float this[int index]
{
get
{
fixed (float* ptr = list)
{
return ptr[index];
}
}
set
{
fixed (float* ptr = list)
{
ptr[index] = value;
}
}
}
public float[] AllProperties
{
get
{
float[] res = new float[Count];
fixed (float* ptr = list)
{
for (int i = 0; i < Count; i++)
{
res[i] = ptr[i];
}
}
return res;
}
set
{
fixed (float* ptr = list)
{
for (int i = 0; i < Count; i++)
{
ptr[i] = value[i];
}
}
}
}
}
Note that reflection should work in your case (like others have answered), but this is just a different approach to the problem (and a very fast one too). The main limitation is what types can be made into pointers in C# (sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool)