I am converting some code from VB.NET to C#. In VB.NET, I have this code:
Dim ind As Foo.Index
Dim ed As Foo.Edit
ind = New Foo.Index
ed = ind.InFunction()
That works. So in C# my code will look like this:
Foo.Index ind;
Foo.Edit ed;
ind = New Foo.Index();
ed = ind.InFunction();
But this doesn't work. I am sure that I did not forget to import namespaces. And now I've been wondering, is there any difference between those two?
EDIT:
And I finally add
ed = New Foo.Edit();
into my C# code, but it also doesn't work. IMHO, I think there is a feature in VB.NET that allows auto initializing in variables (like the comment from Bex below suggests). Is it true?
FINAL:
Seems I do need to show all the code. But I need to talk directly to you as well (or you just install the software of mine). It makes me really confused. Thank you all. Sorry for this kind of newbie question.
C-like languages (like C#) require you follow the pattern of [type] [variable name] at a minimum. C#, using the simplest form of initialization, requires you to use the new keyword.
A simple C# class definition:
class Foo
{
public Foo()
{
}
}
Then, to initialize an instance:
Foo myFooIsStrong = new Foo();
//instantiation
IndexServer.ClientInfo ci = new IndexServer.ClientInfo();
IndexServer.IXServicePortC konst = new IndexServer.IXServicePortC();
IndexServer.IndexServer ix = new IndexServer.IndexServer();
IndexServer.EditInfo ed = new IndexServer.EditInfo();
I don't quite understand what you are asking but this may help.
VB auto initializes a lot of variables and c# doesn't.
So in c# you should initialize your variables.
The problem is that vb.net let's you import namespace roots, while C# requires you to import the full namespace. Your VB code has a statement like this at the top:
Imports MyLibrary
This puts the MyLibrary namespace sort of "in scope", such that you can use the type MyLibrary.Foo.Index either through the full name or by simply saying Foo.Index. C# does not allow this. You must either also import MyLibrary.Foo or reference the entire name in your code.
C# is case sensitive. So the
ed = New Foo.Edit();
should be
ed = new Foo.Edit();
Here's an example
using IndexServer;
...
IndexServer ix = new IndexServer();
ClientInfo ci = new ClientInfo();
EditInfo ed = ix.checkoutSord(ci, Konstanta.EDIT_INFO.mbSord, Konstanta.LOCK.NO);
Without knowing what those classes look like, hard to tell you more. But instantiation is basically the same, just need to change some syntax for declaring variable.
Related
In VB.NET you can use an object initializer and reference the same members on the right hand side, like this:
GetValue.Add(New ArrayIndexInfo() With {
.Type = CType(NvpInfo(Index), Type),
.Name = NvpInfo(Index + 2).ToString,
.NvpValues = CType(.Type.GetField(NvpInfo(Index + 1).ToString).GetValue(Instances.First(Function(o) o IsNot Nothing AndAlso o.GetType = CType(NvpInfo(Index), Type))), NameValuePair())
})
Notice how in the line that sets .NvpValues you can reference .Type and that it's no problem.
But if you try to do that in c# (or like I did, try to convert a project from vb.net to c#), you get an error.
<variable> is not declared
I worked around it like this, which is not DRY because ((Type)NvpInfo[Index]) is repeated:
functionReturnValue.Add(new ArrayIndexInfo {
Type = (Type)NvpInfo[Index],
Name = NvpInfo[Index + 2].ToString(),
NvpValues = (NameValuePair[])((Type)NvpInfo[Index]).GetField(NvpInfo[Index + 1].ToString()).GetValue(Instances.First(o => o != null && o.GetType() == (Type)NvpInfo[Index]))
});
Why doesn't c# allow this? I think it should. I think converting legacy code to c# should be as painless as possible.
Is there a better way that I get around this and still use the object initializer?
To answer the question, I'll base myself on a simplified version of your example
VB.NET:
Dim c = New SomeClass With {
.Prop1 = "abc",
.Prop2 = .Prop1
}
Console.WriteLine(c.Prop1) 'prints "abc"
Console.WriteLine(c.Prop2) 'prints "abc"
C#
var c = new SomeClass
{
Prop1 = "abc",
Prop2 = Prop1 // won't compile. Can't reference Prop1 here.
};
Console.WriteLine(c.Prop1);
Console.WriteLine(c.Prop2);
Addressing your last question:
Is there a better way that I get around this and still use the object initializer?
So one of your concerns is that because C# doesn't allow referencing other properties in an object initialization statement, that it causes you to violate the DRY principle. But really, all you need to do is use variables:
Working C# example that doesn't violate DRY principle:
string temp = "abc";
var c = new SomeClass
{
Prop1 = temp,
Prop2 = temp
};
Console.WriteLine(c.Prop1); // prints "abc"
Console.WriteLine(c.Prop2); // prints "abc"
Why doesn't c# allow this? I think it should.
Obviously, only the designers of the language can truly answer that one. But I can at least share why I like C#'s design decision better. For instance, in the VB.NET version, if I mistakenly initialize the properties in a different order:
Dim c = New SomeClass With {
.Prop2 = .Prop1,
.Prop1 = "abc"
}
Console.WriteLine(c.Prop1) 'prints "abc"
Console.WriteLine(c.Prop2) 'prints nothing
... the code is still "legal" but I've now inadvertently introduced a bug, and Prop2 is now initialized incorrectly.
Because C# disallows this, it prevents most bugs related to the order of property initialization. I agree that in this very simplified example it's hard to imagine anyone falling for that mistake. But with more properties and more complicated initialization statements, it may not be so obvious, and mistakes can more easily be made. C# helps you avoid these subtle bugs.
I think converting legacy code to c# should be as painless as possible.
I guess you're implying that VB.NET is a legacy language? Some may take offense :)
But more seriously, are you implying that language design decisions should be made to facilitate migration from other languages? C# and VB.NET are two full featured languages in their own right. They are not meant to have matching and symmetrical language designs. If they did, what would be the point of having 2 separate languages?
No. They are 2 different languages with 2 different philosophies. We should consider ourselves lucky that the migration path is as easy as it is currently. There is no reason why it needs to be.
I'm trying to create a small code generator using Roslyn or as it is called now .NET Compiler Platform, prevously I worked with codedom, which was cumbersome but MSDN got a reference, now Roslyn has little documentation and all documentation is focused on code analysis instead of code generation.
So my question is simple:
How can I create something like:
private const string MyString = "This is my string";
using the Compiler Platform classes? I've found something like FieldDeclarationSyntax and ExpressionSyntax, but all samples I've found generate things like
Myclass myvariable = new Myclass();
And there is nothing telling me something so simple as how to produce the
string type declaration.
any clue will be great.
Thank you in advance
You can use Roslyn Quoter to easily figure out how to build different pieces of syntax. In this case you're wanting to add the const and private modifiers to a field declaration so it would look something like:
var constField = SyntaxFactory.FieldDeclaration(
SyntaxFactory.VariableDeclaration(
SyntaxFactory.PredefinedType(
SyntaxFactory.Token(SyntaxKind.StringKeyword)))
.WithVariables(
SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(
SyntaxFactory.VariableDeclarator(
SyntaxFactory.Identifier("MyString"))
.WithInitializer(
SyntaxFactory.EqualsValueClause(
SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal("This is my string")))))))
.WithModifiers(
SyntaxFactory.TokenList(
new []{
SyntaxFactory.Token(SyntaxKind.PrivateKeyword),
SyntaxFactory.Token(SyntaxKind.ConstKeyword)}))))))
I have some old VB code to send mails using Lotus Notes that works, I have re-written it into C#, but it behaves differently:
VB:
NotesSession = CreateObject("Notes.Notessession")
NotesDb = NotesSession.GetDatabase("", "")
C#:
_notesSession = new NotesSession();
_notesSession.Initialize(passwordString);
_notesDatabase = _notesSession.GetDatabase( "", "");
First of in C# I need to Initialize the NotesSession with a password, and secondly it will not accept empty string parameters at runtime. Exception is thrown: "A database name must be provided".
In both VB and C# I refer to the same COM : Lotus Domino Objects
I need to be able to call the GetDatabase without specifying the server and database file.
Thanks in advance.
Solution (Thanks guys):
dynamic _notesSession = Activator.CreateInstance(Type.GetTypeFromProgID("Notes.NotesSession"));
_notesDatabase = _notesSession.GetDatabase("", "");
This way you have no intellisense but all properties and methods can be found here
When you create a new instance of the NoteSession type in C# using the new keyword, it will use the COM-interop dll that was referenced by the project at build-time. That is not exactly the same thing as calling CreateObject, which requires no interop dll. The closer equivalent in C# would be:
Type t = Type.GetTypeFromProgID("Notes.Notessession");
_notesSession = Activator.CreateInstance(t);
Or, if you really need to do the exact same thing, you could always add a reference to the Microsoft.VisualBasic.dll library and then call the Microsoft.VisualBasic.Interaction.CreateObject method from C#.
As Richard pointed out in the comments below, the likely reason why you are seeing a difference in behavior is because you are creating two different types of objects. Presumably, when you call new NotesSession in C#, it is using the NotesSession class from the Lotus namespace, rather than the one in the Notes namespace.
I followed the link of parse CSV using F# and filehelpers. got compiler error for the following code "The record class oneRow need a constructor with no args (public or private)"
[<DelimitedRecord(",")>]
type oneRow=
class
[<FieldConverter(ConverterKind.Date, "M/d/yyyy")>]
val date: DateTime
val value: bool
end
let engine = new FileHelperEngine(typeof<oneRow>)
let tmp = engine.ReadFile("test.csv")
EDIT
The solution looks quite verbose than c# version. I need add (), mutable and [<DefaultValue>]
type oneRow() =
class
[<FieldConverter(ConverterKind.Date, "M/d/yyyy")>]
[<DefaultValue>]
val mutable date: DateTime
[<DefaultValue>]
val mutable value: bool
end
But similar code works in C# without specify a constructor. Could anyone help me fix the F# code? thanks.
C# will create you a constructor. F# doesn't (presumably because parameterless constructors imply mutability, and so are not exactly encouraged.)
For example, in your code - how are you going to set those properties, they're still immutable.
Regarding the verbose syntax - It can be made nicer. The sample was written some time ago (2 years), so it is still using a little old syntax. It could be updated to allow writing something like this:
[<DelimitedRecord(",")>]
type OneRow
( [<FieldConverter(ConverterKind.Date, "M/d/yyyy")>]
date:DateTime,
value:bool ) =
member x.Date = date
member x.Value = value
I believe this is a lot nicer (and by moving annotations to the constructor, you can also implement your own functionality in the type and e.g. hide some fields). The only change that needs to be done is to modify the parser to find attributes on constructor parameters (and not fields).
Based on the error message, i think it would work if a ctor is added into oneRow.
new () = { date = new DateTime() ; value = false}
yes, it should be type oneRow () = with parentheses
Most of the posts concerning FileHelpers are rather dated. In some cases though it's nice to use instead of the csv type provider. One can use the CLIMutable attribute on an F# record to have a default constructor and in this case FileHelpers will happily write and read the csv file:
#if INTERACTIVE
#I #"..\packages\FileHelpers\lib\net45"
#r "FileHelpers.dll"
#endif
open FileHelpers
open System
[<DelimitedRecord(",");CLIMutable>]
type TestFileHelp =
{test1:string
test2:string
[<FieldConverter(ConverterKind.Date, "yyyy/MM/dd")>]
date:DateTime
}
let f1 = [|{test1="a";test2="b";date=DateTime.Now};{test1="c";test2="d";date=DateTime.Now}|]
let fengine = new FileHelperEngine<TestFileHelp>()
fengine.WriteFile(#"c:\tmp\testrec.csv",f1)
I have one question, I have such code
this._engine = Python.CreateEngine();
ScriptSource source = this._engine.CreateScriptSourceFromString(script.SourceCode);
ScriptScope scope = this._engine.CreateScope();
ObjectOperations operations = this._engine.Operations;
source.Execute(scope);
And I am trying to execute IronPython code from tutorial:
from System.Collections import BitArray
ba = BitArray(5)
ba.Set(0, True) # call the Set method
print ba[0]
So it executes correctly, but I can't understand if i have print ba[0] why it doesn't output this value to the console? By the way, could you advice some good articles about using IronPython for applications scripting?
And another question is if I have some Python class and I do not know the name of this class, because the client can define it manually, is it possible to create an instance of this class? For example
class SomeClass(object):
def some(self, a, b):
return <something>
Now I'm trying to use this code
dynamic SomeClass = scope.GetVariable("SomeClass");
dynamic something = SomeClass();
something.some(x,y);
Should I iterate through ScriptScope.GetItems() collection and search for PythonType objects?
I think you just need to call:
this._engine.Runtime.IO.RedirectToConsole();
Otherwise have a look here for a similar question about redirecting.
About python class instantiation in C#, your code seems to be ok, as shown in this question (look at the 3rd answer)
EDIT:
Sorry I didn't read your question with enough attention...
Anyway, to look for available classes in Python, just do as you said,
i.e. something like:
var availDynClasses = items.Where(x => x.Value is IronPython.Runtime.Types.PythonType);