I had problems implementing this API in Visual Basic, and i had to modify the C# version of the api to work in VB.NET. The major problems are the ambiguous type (DB and Db) and the way the Serialize and Deserialize methods are declared, because VB.NET can't figure which to use in which case. The way I take out this problems was renaming the methods and the Db statement. If any ones wants a version ready to build, send me an email. I will kep an eye in this project, and if the owner of the project wants, publish the vb.net version here.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am interested in your modifications, as I would like the API to be usable from VB without changes.
If you could send me a diff, or a list of things you did then I may be able to incorporate them in some way into the C# code.
I understand that VB is not case sensitive, so I should have remembered that when defining the API.
Also, could you explain the Serialize issues - my VB days are so far back that I barely remember it.
Karl
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok, the changes are not already maked or listed, because I still don't use all the functions of the API, so i will keep updating if theres is another changes. The ones I made so far are:
-Changed the Db type to Database, in the examples you dont declare a database of type Db, now I declare of type Database.
-The serialization issues are mainly caused for VB.NET IDE, because can't figure wich type of serializer/deserializer to use. For example, I converted the examples to VB.NET using the Sharp Develop's Converter (a good one to convert entire projects in one step), and when converted, in the serialize part, VB.NET give to me an error saying "string don't fullfill the requirement of Type struct in the serialize(of T)", and in the deserialize part, one saying "Integer don't fullfill the requirement of type class in the deserialize(of T)", here, I only renamed the metods to let VB.NET know which one to use, But still the names are provisional.
I sill don't use the FromDBEntry and ToDBentry methods of the formater, and I imagine i need to change this. I will kep you updated of any other change needed.
Adair
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I forgot to say that there is in fact, the C# version can be used in the way is writed now. I'm working in a generic class that simulate some structures in provided by the framework, like the hashtable, but with a DB in BerleyeDB. I this case, I need to use the serialize and deserialize functions in the way that are now (same name, but diferent fuction inside). So maybe we need to keep the to versions alive.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I did one thing in my source, I renamed DB to DB_ and left Db as it is. That way we have no name conflict, and both show up in VB.NET. I think that should work and also requires no change to the public API (the DB_ struct should normally not be used anyway).
About the Serialize() issue: Are you saying that the compiler can handle it, but the IDE gets confused?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The issue in the serialize is that both the compiler and the IDE (mainly because we tried to compile it using the Framework SDK without IDE) can't figure wich one to use, actually, VB don't supor the Where statement in the serialize declaration (it appears VB ignore this or take wathever it wants). Even when the where declares struct or class.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I sent the example to your email. I managed to convert my classes to c#, and i still get the error of the serialize and in the toDBentry. the ide Give to me this error: The type 'TData' must be a reference type in order to use it as parameter 'T' in the generic type or method 'BerkeleyDb.Serialization.BdbFormatter.ToDbEntry<T>(T)'
This is my code:
public bool Add<TKey,TData>(ref TKey KeyString,ref TData StringValue)
where TKey :class
where TData : struct
{
DbEntry key = m_fmt.ToDbEntry<TKey >(KeyString);
DbEntry data = m_fmt.ToDbEntry<TData >(StringValue);
The error text is this one: The type 'TData' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Kds.Serialization.Formatter<F>.Deserialize<T>(ref T)'
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The type 'TData' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Kds.Serialization.Formatter<F>.Deserialize<T>(ref T)'
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The problem is similar to the other problem.
There are three signatures for deserializing a single instance:
public T? Deserialize<T>() where T: struct
public void Deserialize<T>(ref T value, out bool isNull) where T: struct
public void Deserialize<T>(ref T obj) where T: class
Your call matches the third one, but you are using a struct type.
However, since deserialization can return null, we need to deal
with it differently for structs. We have two choices, use a nullable
struct (first signature), or return a second boolean value, isNull.
Karl
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok, i Got an Idea an is working!!!!. Actually I'm Using the same Version of the API for my C# code and the VB.NET code. I made a more radical modification in te library (One must be the DB and Db change). I declared 2 groups of each serialize and deserialize methods. Then, I have the deserialize for c# (like your API) and a copy with the name changed for VB.NET. This is working, i have another problem, but is in another part.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I Found a bug(???), but i don't know if it is really a bug, and don't know if this is a bug in the API or BerkeleyDB. When i use the Get method for a String,[Custom] pair, Can't get back the first record. I debugged the program and is inserting it, but when i call the get function, all thath i got is not found (even if i call more than 1 looking for the first record.).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OK, it is a bug, but a tricky one. At the end of the buffer I have an array of bits that indicates which fields are null.
In the last byte, some bits are not used, and my code didn't care about their value, but obviously Berkely Db does.
I hope this fix works - for file BufferSerialization.cs:
Add this declaration somewhere before FinishSerialization:
public int FinishSerialization() {
// save status buffer for re-use
statusBuf = statusBuffer;
int bufIndx = startIndx;
// size should not include prefix size!
int bufSize = valueIndx - bufIndx - sizeof(uint);
// write length prefix to start of value buffer
BEConverter.ToBytes(bufSize, valueBuffer, ref bufIndx);
int endIndex = valueIndx + nextStatusByte(statusIndx);
if (valueBuffer.Length < endIndex)
throw new IndexOutOfRangeException("Buffer size too small.");
// clear unused bits in status buffer
if (statusIndx > 0)
unchecked {
int lastStatusIndx = statusIndx - 1;
int lastByteIndex = lastStatusIndx >> 2;
statusBuffer[lastByteIndex] &= clearMasks[lastStatusIndx & twoBitIndexMask];
}
Ok, i'll send to you, but actually is a dll the one who works with the DB. I'll send you all the package (Example using my dll, and the new versions of the dlls for VB.NET and C#), the las change inside my version of the API is the DB and Db change, but you can check all the changes I made to keep it working for Both VB and C#
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have one more cuestion, how can i define a custom field type (like in the examples), but inside the library or in another proyect, this because i need tou use a strucuture (like the one in my cuestions) but the user don't want to change their original code (thats why the library for the library)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I had problems implementing this API in Visual Basic, and i had to modify the C# version of the api to work in VB.NET. The major problems are the ambiguous type (DB and Db) and the way the Serialize and Deserialize methods are declared, because VB.NET can't figure which to use in which case. The way I take out this problems was renaming the methods and the Db statement. If any ones wants a version ready to build, send me an email. I will kep an eye in this project, and if the owner of the project wants, publish the vb.net version here.
Hi Adair,
I am interested in your modifications, as I would like the API to be usable from VB without changes.
If you could send me a diff, or a list of things you did then I may be able to incorporate them in some way into the C# code.
I understand that VB is not case sensitive, so I should have remembered that when defining the API.
Also, could you explain the Serialize issues - my VB days are so far back that I barely remember it.
Karl
Ok, the changes are not already maked or listed, because I still don't use all the functions of the API, so i will keep updating if theres is another changes. The ones I made so far are:
-Changed the Db type to Database, in the examples you dont declare a database of type Db, now I declare of type Database.
-The serialization issues are mainly caused for VB.NET IDE, because can't figure wich type of serializer/deserializer to use. For example, I converted the examples to VB.NET using the Sharp Develop's Converter (a good one to convert entire projects in one step), and when converted, in the serialize part, VB.NET give to me an error saying "string don't fullfill the requirement of Type struct in the serialize(of T)", and in the deserialize part, one saying "Integer don't fullfill the requirement of type class in the deserialize(of T)", here, I only renamed the metods to let VB.NET know which one to use, But still the names are provisional.
I sill don't use the FromDBEntry and ToDBentry methods of the formater, and I imagine i need to change this. I will kep you updated of any other change needed.
Adair
I forgot to say that there is in fact, the C# version can be used in the way is writed now. I'm working in a generic class that simulate some structures in provided by the framework, like the hashtable, but with a DB in BerleyeDB. I this case, I need to use the serialize and deserialize functions in the way that are now (same name, but diferent fuction inside). So maybe we need to keep the to versions alive.
I did one thing in my source, I renamed DB to DB_ and left Db as it is. That way we have no name conflict, and both show up in VB.NET. I think that should work and also requires no change to the public API (the DB_ struct should normally not be used anyway).
About the Serialize() issue: Are you saying that the compiler can handle it, but the IDE gets confused?
Ok, the change in the Db and DB is ok.
The issue in the serialize is that both the compiler and the IDE (mainly because we tried to compile it using the Framework SDK without IDE) can't figure wich one to use, actually, VB don't supor the Where statement in the serialize declaration (it appears VB ignore this or take wathever it wants). Even when the where declares struct or class.
Well, I declared the serialization Dll as CLS compliant, so it should work with VB.
Can you send me a small demo app that has the problem?
Thanks,
Karl
Ok, I'll send you an example (one of your demos in a VB.Net conversion), but can you give me your file so i can Send you the entire project.
OK, my e-mail is karl at waclawek.net (replace the 'at).
I sent the example to your email. I managed to convert my classes to c#, and i still get the error of the serialize and in the toDBentry. the ide Give to me this error: The type 'TData' must be a reference type in order to use it as parameter 'T' in the generic type or method 'BerkeleyDb.Serialization.BdbFormatter.ToDbEntry<T>(T)'
This is my code:
public bool Add<TKey,TData>(ref TKey KeyString,ref TData StringValue)
where TKey :class
where TData : struct
{
DbEntry key = m_fmt.ToDbEntry<TKey >(KeyString);
DbEntry data = m_fmt.ToDbEntry<TData >(StringValue);
try
{
myObject.PutNew(null, ref key, ref data);
RecordCount += 1;
}
catch (BerkeleyDb.BdbException ex)
{
throw new FinamexDBException("Imposible adicionar registro", ex);
}
return System.Convert.ToBoolean(WriteStatus.Success);
}
Hard to tell - are you using your build of the serialization assembly, or my build?
It took me a while, but the solution is this:
DbEntry data = m_fmt.ToDbEntry<TData >(ref StringValue);
Without the ref it does not match the signature of ToDbEntry for struct parameters!
I solved this one, but i get another with a deserialize. The code looks like this:
public TData GetValue<TKey, TData>(TKey KeyString)
where TKey : class
where TData : struct
{
byte[] tempBuffer = new byte[1025];
DbEntry key = m_fmt.ToDbEntry<TKey >(KeyString);
DbEntry data = DbEntry.Out(tempBuffer);
ReadStatus status;
try
{
status = myObject.Get(null, ref key, ref data, BerkeleyDb.DbFile.ReadFlags.None);
}
catch (BerkeleyDb.BdbException ex)
{
status = ReadStatus.NotFound;
throw new FinamexDBException("Imposible obtener registro", ex);
}
if (status == ReadStatus.Success)
{
TData Result = default(TData ) ;
m_fmt.InitDeserialization(data.Buffer, data.Start);
try
{
m_fmt.Deserialize<TData >(ref Result);
}
catch (BerkeleyDb.BdbException ex)
{
throw new FinamexDBException("Imposible desserializar texto", ex);
}
return Result;
}
else
{
return default(TData );
}
}
The error text is this one: The type 'TData' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Kds.Serialization.Formatter<F>.Deserialize<T>(ref T)'
Sorry Karl, but i poste the wrong code for my promblem, the right one is:
public TData GetValue<TKey, TData>(TKey KeyString)
where TKey : class
where TData : struct
{
byte[] tempBuffer = new byte[1025];
DbEntry key = m_fmt.ToDbEntry<TKey >(KeyString);
DbEntry data = DbEntry.Out(tempBuffer);
ReadStatus status;
try
{
status = myObject.Get(null, ref key, ref data, BerkeleyDb.DbFile.ReadFlags.None);
}
catch (BerkeleyDb.BdbException ex)
{
status = ReadStatus.NotFound;
throw new FinamexDBException("Imposible obtener registro", ex);
}
if (status == ReadStatus.Success)
{
TData Result = default(TData ) ;
m_fmt.InitDeserialization(data.Buffer, data.Start);
try
{
m_fmt.Deserialize<TData >(ref Result);
}
catch (BerkeleyDb.BdbException ex)
{
throw new FinamexDBException("Imposible desserializar texto", ex);
}
return Result;
}
else
{
return default(TData );
}
}
and the problem is :
The type 'TData' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Kds.Serialization.Formatter<F>.Deserialize<T>(ref T)'
The problem is similar to the other problem.
There are three signatures for deserializing a single instance:
public T? Deserialize<T>() where T: struct
public void Deserialize<T>(ref T value, out bool isNull) where T: struct
public void Deserialize<T>(ref T obj) where T: class
Your call matches the third one, but you are using a struct type.
However, since deserialization can return null, we need to deal
with it differently for structs. We have two choices, use a nullable
struct (first signature), or return a second boolean value, isNull.
Karl
I made it, but now, i have a question: How can i make this to work with a structure of this type:
Public Structure Valores
Public i As String
Public t As String
end strucutre
This should work:
struct Valores {
public string i;
public string t;
}
public class ValoresField: ValueField<Valores>
{
public ValoresField(Formatter fmt, bool isDefault) : base(fmt, isDefault) { }
protected override void DeserializeValue(ref Valores value) {
Fmt.Deserialize<string>(value.i);
Fmt.Deserialize<string>(value.t);
}
protected override void SerializeValue(ref Valores value) {
Fmt.Serialize<string>(value.i);
Fmt.Serialize<string>(value.t);
}
protected override void SkipValue() {
if (Fmt.Skip<string>())
Fmt.Skip<string>();
}
}
Better explanation is in the docs.
Karl
Sorry, small correction:
Fmt.Deserialize<string>(ref value.i);
Fmt.Deserialize<string>(ref value.t);
Karl
Ok, i Got an Idea an is working!!!!. Actually I'm Using the same Version of the API for my C# code and the VB.NET code. I made a more radical modification in te library (One must be the DB and Db change). I declared 2 groups of each serialize and deserialize methods. Then, I have the deserialize for c# (like your API) and a copy with the name changed for VB.NET. This is working, i have another problem, but is in another part.
I Found a bug(???), but i don't know if it is really a bug, and don't know if this is a bug in the API or BerkeleyDB. When i use the Get method for a String,[Custom] pair, Can't get back the first record. I debugged the program and is inserting it, but when i call the get function, all thath i got is not found (even if i call more than 1 looking for the first record.).
Well, most often it is not a Berkeley DB error.
Could you send me a (small) program that shows the bug?
OK, it is a bug, but a tricky one. At the end of the buffer I have an array of bits that indicates which fields are null.
In the last byte, some bits are not used, and my code didn't care about their value, but obviously Berkely Db does.
I hope this fix works - for file BufferSerialization.cs:
Add this declaration somewhere before FinishSerialization:
/// <summary>Bitmask for clearing unused <see cref="SerialStatus"/> values.</summary>
protected static readonly byte[] clearMasks = { 0x03, 0x0F, 0x3F, 0xFF };
Then replace FinishSerialization with this code:
public int FinishSerialization() {
// save status buffer for re-use
statusBuf = statusBuffer;
int bufIndx = startIndx;
// size should not include prefix size!
int bufSize = valueIndx - bufIndx - sizeof(uint);
// write length prefix to start of value buffer
BEConverter.ToBytes(bufSize, valueBuffer, ref bufIndx);
int endIndex = valueIndx + nextStatusByte(statusIndx);
if (valueBuffer.Length < endIndex)
throw new IndexOutOfRangeException("Buffer size too small.");
// clear unused bits in status buffer
if (statusIndx > 0)
unchecked {
int lastStatusIndx = statusIndx - 1;
int lastByteIndex = lastStatusIndx >> 2;
statusBuffer[lastByteIndex] &= clearMasks[lastStatusIndx & twoBitIndexMask];
}
// copy status buffer
bufIndx = valueIndx;
bufSize = nextStatusByte(statusIndx);
System.Buffer.BlockCopy(statusBuffer, 0, valueBuffer, bufIndx, bufSize);
valueBuffer = null;
return endIndex;
}
Hope it works.
Karl
Ok, i'll send to you, but actually is a dll the one who works with the DB. I'll send you all the package (Example using my dll, and the new versions of the dlls for VB.NET and C#), the las change inside my version of the API is the DB and Db change, but you can check all the changes I made to keep it working for Both VB and C#
I have one more cuestion, how can i define a custom field type (like in the examples), but inside the library or in another proyect, this because i need tou use a strucuture (like the one in my cuestions) but the user don't want to change their original code (thats why the library for the library)
Just define it and register it with the formatter. There is some explanations in the docs.