I recently tried Protobuf-net r668 with my vb.net code. I can mark attributes on my data class but can't get the Serialize and Deserialize features to work.
I followed the instructions at http://code.google.com/p/protobuf-net/wiki/GettingStarted but having converted the code to vb.net I found that this C# code:
using (var file = File.Create("person.bin")) {
Serializer.Serialize(file, person);
}
Won't work when translated to vb.net because the Serialize method does not show up as a method of class Protobuf.Serializer.
Any pointers from anyone who has got Protobuf-net working in vb.net would be helpful.
It should just work; the following runs fine, for example:
Imports System.IO
Module Module1
Sub Main()
Dim strFileName As String = "foo.bin"
Dim f As FileStream = File.Create(strFileName)
Dim objData As Foo = New Foo With {.Name = "abcdef"}
ProtoBuf.Serializer.Serialize(f, objData)
End Sub
<ProtoBuf.ProtoContract>
Class Foo
<ProtoBuf.ProtoMember(1)>
Property Name As String
End Class
End Module
My initial thought is that you have referenced a version of the protobuf-net.dll that is intended for one of the mobile platforms, which expose some features slightly differently. Specifically, a dll from the "core only" build. The intended purpose of each different build is described in the What Files Do I Need.txt file (which is include in the root of the package)
Related
I have created a VB .NET application that opens files in their default application - extracts information and returns it to a listview on a form.
All of the code is in my main form. The main form has in it
Imports Microsoft.Office.Core
Imports Microsoft.Office.Interop.Word
Imports Microsoft.Office.Interop.Excel
If in the future I want to modify my software to include another filetype not thought of in this release, am I better off for all of the filetypes I wish to open (including office) adding new classes for each filetype and including the 'Imports' in the individual classes?
So for example I would have:
OpenFileDWG.vb
Imports Autodesk.AutoCAD.Runtime
OpenFileDOC.vb
Imports Microsoft.Office.Interop.Word
etc. etc.
Is this a standard approach? If I were to do this, could I use:
If exists LCase(My.Computer.FileSystem.GetFileInfo(Filepath).Extension) THEN
strFileOpener = OpenFileDWG & Extension
Private fileOpener As strFileOpener
Would this approach work, or would I still need to reference the .dll in the main application, making this approach unworthy?
If I were to use this approach, could I just give the .vb file as part of an update?
Any advice is much appreciated.
Seems to me like a classing case to use factory design pattern
Basically, the factory design pattern provides loose coupling between the factory created classes and the class that uses them.
Begin by separating the different file types to different classes, and have them all inherit a basic abstract class (MustInherit in vb.net).
Then create an factory class to create create the concrete implementation of every file reader class. (meaning for each file type).
I'll try to illustrate with a simple example:
'' Defines an abstract class that all FileReaders should inherit
Public MustInherit Class FileReader
Public MustOverride Function ReadFileContent(Path As String) As String
End Class
Now, all of the classes for reading files must inherit the FileReader class:
Public Class WordFileReader
Inherits FileReader
Public Override Function ReadFileContent(Path As String) As String
'' TODO: Add code to read the content of the word document and return it as a string.
End Function
End Class
Public Class ExcelFileReader
Inherits FileReader
Public Override Function ReadFileContent(Path As String) As String
'' TODO: Add code to read the content of the excel file and return it as a string.
End Function
End Class
Then you can use a simple factory method (read here to learn about the difference between factory methods and abstract factories) to create your classes:
Enum FileTypes
Word,
Excel
End Enum
Public Function GetFileReader(FileType As FileTypes) As FileReader
Dim FileReader as FileReader = Nothing
Select case FileType
Case FileTypes.Word:
FileReader = New WordFileReader()
Case FileTypes.Excel:
FileReader = New ExcelFileReader()
End Select
Return FileReader
End Function
To enable new file types add-ins you can use MEF to load the concrete classes.
I am trying to follow this sample code for C++, but the line:
Using namespace System::Security::Cryptography;
throws an error in VS 2013 pro. The word System is underlined in red and the mouse-over message says: "name followed by '::' must be a class or namespace name". I have working code using the HMACSHA1 class in several languages (C#, VB.net, python, etc) but can't get it working in C++. What is the problem with accessing this class in C++? Should I be using a different namespace, or adding an #include for some file? I have seen an example of using the HMAC class in C, but that is an "abstract class" and appears that it would require a lot more work to get what I want. I don't understand why I can't use the HMACSHA1 class which delivers exactly what I need.
(Just in case someone asks, my working vb.net code looks like this:
Private Function GetApi_Sig()
Dim api_sig As String = ""
Using myhmac As New HMACSHA1(System.Text.Encoding.UTF8.GetBytes(secret))
Dim hashValue As Byte() = myhmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(key))
Dim i As Integer
For i = 0 To (hashValue.Length - 1)
api_sig = api_sig + String.Format("{0:x2}", hashValue(i))
Next i
End Using
Return api_sig
End Function 'GetApi_Sig
)
suppose I declare a class like this:
Class tst
Public Props As New Dictionary(Of String, MyProp)
End Class
and added properties something along these lines:
Dim t As New tst
t.Props.Add("Source", new MyProp(3))
but now want to access it like this:
t.Source
how can I create a getter without knowing the name of the getter?
Ok, if you insist on "auto-vivifying", the only way I know of to do something like that is to generate the code as a string, and then compile it at runtime using the classes in the System.CodeDom.Compiler namespace. I've only ever used it to generate complete classes from scratch, so I don't know if you could even get it to work for what need to add properties to an already existing class, but perhaps you could if you compiled extension methods at runtime.
The .NET framework includes multiple implementations of the CodeDomeProvider class, one for each language. You will most likely be interested in the Microsoft.VisualBasic.VBCodeProvider class.
First, you'll need to create a CompilerParameters object. You'll want to fill its ReferencedAssemblies collection property with a list of all the libraries your generated code will need to reference. Set the GenerateExecutable property to False. Set GenerateInMemory to True.
Next, you'll need to create a string with the source code you want to compile. Then, call CompileAssemblyFromSource, passing it the CompilerParameters object and the string of source code.
The CompileAssemblyFromSource method will return a CompilerResults object. The Errors collection contains a list of compile errors, if there are any, and the CompiledAssembly property will be a reference to your compiled library (as an Assembly object). To create an instance of your dynamically compiled class, call the CompiledAssembly.CreateInstance method.
If you're just generating a small amount of code, it's pretty quick to compile it. But if it's a lot of code, you may notice an impact on performance.
Here's a simple example of how to generate a dynamic class containing a single dynamic property:
Option Strict Off
Imports System.CodeDom.Compiler
Imports Microsoft.VisualBasic
Imports System.Text
Public Class Form3
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim code As StringBuilder = New StringBuilder()
code.AppendLine("Namespace MyDynamicNamespace")
code.AppendLine(" Public Class MyDynamicClass")
code.AppendLine(" Public ReadOnly Property WelcomeMessage() As String")
code.AppendLine(" Get")
code.AppendLine(" Return ""Hello World""")
code.AppendLine(" End Get")
code.AppendLine(" End Property")
code.AppendLine(" End Class")
code.AppendLine("End Namespace")
Dim myDynamicObject As Object = generateObject(code.ToString(), "MyDynamicNamespace.MyDynamicClass")
MessageBox.Show(myDynamicObject.WelcomeMessage)
End Sub
Private Function generateObject(ByVal code As String, ByVal typeName As String) As Object
Dim parameters As CompilerParameters = New CompilerParameters()
parameters.ReferencedAssemblies.Add("System.dll")
parameters.GenerateInMemory = True
parameters.GenerateExecutable = False
Dim provider As VBCodeProvider = New VBCodeProvider()
Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, code)
If results.Errors.HasErrors Then
Throw New Exception("Failed to compile dynamic class")
End If
Return results.CompiledAssembly.CreateInstance(typeName)
End Function
End Class
Note, I never use Option Strict Off, but for the sake of simplicity in this example, I turned it off so I could simply call myDynamicObject.WelcomeMessage without writing all the reflection code myself.
Calling methods on objects using reflection can be painful and dangerous. Therefore, it can be helpful to provide a base class or interface in a shared assembly which is referenced by both the generated assembly, and the fixed assembly which calls the generated assembly. That way, you can use the dynamically generated objects through a strongly typed interface.
I figured based on your question that you were just more used to dynamic languages like JavaScript, so you were just thinking of a solution using the wrong mindset, not that you really needed to or even should be doing it this way. But, it is definitely useful in some situations to know how to do this in .NET. It's definitely not something you want to be doing on a regular basis, but, if you need to support custom scripts to perform complex validation or data transformations, something like this can be very useful.
Long term lurker, first time poster here.
I have written a class to model an object in vb.net, using vs2008 and framework 2.0. I am serializing the class to an XML file for persistent storage. I do this with a method in the class like this:
Public Sub SaveAs(ByVal filename As String)
Dim writer As New Xml.Serialization.XmlSerializer(GetType(MyNamespace.MyClass))
Dim file As New System.IO.StreamWriter(filename)
writer.Serialize(file, Me)
file.Close()
End Sub
I now want to do a similar thing but reading the class from file to the current instance, like this:
Public Sub New(ByVal filename As String)
Dim reader = New Xml.Serialization.XmlSerializer(GetType(MyNamespace.MyClass))
Dim file = New System.IO.StreamReader(FullPath)
Me = CType(reader.Deserialize(file), MyNamespace.MyClass)
End Sub
However, I cannot assign anything to “Me”. I’ve tried creating a temporary object to hold the file contents then copying each property and field over to the current instance. I iterated over the properties (using Reflection), but this soon gets messy, dealing with ReadOnly collection properties, for example. If I just copy each property manually I will have to remember to modify the procedure whenever I add a property in the future, so that sounds like a recipe for disaster.
I know that I could just use a separate function outside the class but many built-in .NET classes can instantiate themselves from file e.g. Dim bmp As New Bitmap(filename As String) and this seems very intuitive to me.
So can anyone suggest how to load a class into the current instance in the Sub New procedure? Many thanks in advance for any advice.
I'd put a shared load function on the class, that returned the newly de-serialised object.
e.g.
Public Class MyClass
...
Public shared Function Load(ByVal filename As String) as MyClass
Dim reader = New Xml.Serialization.XmlSerializer(GetType(MyNamespace.MyClass))
Dim file = New System.IO.StreamReader(FullPath)
Return CType(reader.Deserialize(file), MyNamespace.MyClass)
End Sub
End Class
...
Dim mine as MyClass = MyClass.Load("MyObject.Xml");
Hope this helps
Alternatively,
Encapsulate the data of your class in an inner, private class.
The properties on your outer visible class delegate to the inner class.
Then Serialising and De-serialising happens on the inner class, you can then have a ctor that takes the file name, de-serialises the inner hidden object, and assigns it to the classes data store.
The "New" method in VB.Net is a constructor for the class. You can't call it for an existing instance, as the whole purpose of the method is to create new instances; it's just not how the language works. Try naming the method something like "ReadFrom" or "LoadFrom" instead.
Additionally, given those methods, I would try to implement them using a Factory Pattern. The ReadFrom method would be marked Shared and return the new instance. I would also make the method more generic. My main ReadFrom() method would accept an open textreader or xmlreader or even just a stream, rather than a file name. I would then have overloads that converts a file name into a stream for reading and calls the main method.
Of course, that assumes I use that pattern in the first place. .Net already has great support for xml serialization built into the platform. Look into the System.Xml.Serialization.XmlSerializer class and associated features.
I am trying to make my own Labeller plugin for Cruise Control .Net 1.4.3. I have made a class based on another plug in example but I keep getting an error
Class 'AssemblyVersionLabeller' must implement 'Function Generate(integrationResult As IIntegrationResult) As String' for interface 'ThoughtWorks.CruiseControl.Core.ILabeller'
Here is my code :
Imports Exortech.NetReflector
Imports ThoughtWorks.CruiseControl.Core
Imports ThoughtWorks.CruiseControl.Core.Util
Namespace NetAssembly.CCNet.Label
_
Public Class AssemblyVersionLabeller
Implements ILabeller
Public Sub Run(ByVal result As IIntegrationResult)
result.Label = Generate(result)
End Sub
Public Function Generate(ByVal integrationResult As IIntegrationResult) As String
Dim label As String = integrationResult.LastIntegration.Label
Return label
End Function
<ReflectorProperty("prefix", Required:=False)> _
Public Prefix As String = String.Empty
End Class
End Namespace
What am I doing wrong? What have I missed?
Background Info:
I am using VS2005. I cant use CrusieControl 1.4.4 RC2 (which has an Assembly Labeller) because my source control's plugin (SCM Anywhere) doesnt work with it.
I cannot judge just by looking at your code, but if you need a sample on how to write labellers (C# code though), you could take a look at BrekiLabeller code (written by me).
I believe you forgot the overrides decleration..
Public Overrides Function Generate