How do I define a constant Char value, similar to vbCr? This does not work...
Public Const ctrM As Char = "\m"C
This says the constant must have exactly one character. Well, ok, isn't that what "\m" is?, what about the following
Public Const ctrM as Char = Convert.ToChar(9)
That's not allowed because it's a function. Huh. Luckily this does work:
Public Dim ctrM as Char = Convert.ToChar(9)
But this seems sub-optimal. Am I missing something here?
The answer by fsintegral is fine, but can be slightly simpler. And you can use the Framework functions if you prefer them to the VB Functions.
Class method:
Public Class AppConsts
Public Shared ReadOnly CtrlEM As Char = Convert.ToChar(25)
Public Shared ReadOnly CtrlT As Char = Convert.ToChar(9)
Public Shared ReadOnly CtrlN As Char = Convert.ToChar(10)
Public Shared ReadOnly CtrlM As Char = Convert.ToChar(13)
Public Shared ReadOnly CrLf As String = CtrlN & CtrlM
...
End Class
'Usage:
Dim s as string = "..." & AppConts.CtrlEM
They will even show up in intellisense. If you dont like the Type/Class name intruding, you can import the class (I kind of like the Type portion included because it narrows the IntelliSense list rapidly to the relevant values):
Imports AppConsts
....
Dim s As String = CtrlEM
Alternatively, you can use the module method:
Module Program
Friend ReadOnly CtrlM As Char = Convert.ToChar(25)
End Module
' usage:
Dim s2 As String = "xxxx..." & CtrlM
They are not really constants as far as how the compiler treats them at compile time because they aren't -- they are just ReadOnly fields. But as far as your code is concerned in the IDE, they will act, feel and taste like constants.
It is the use of Const statement which limits how you can define them and require you to use (some) the VB functions rather than .NET ones.
Replace:
Public Const ctrM as Char = "\m"C
for this:
Public Const ctrM As Char = "m"c
Credits goes to Plutonix for giving a working/workable solution in a comment.
Used the following approach when I made large use of Modules long ago.
Add a Public Module to your Project :
Public Module MyConsts
' Define your constant Char
Public Const vbTabC As Char = Microsoft.VisualBasic.Chr(9) ' For Tabulation
Public Const vbEMC As Char = Microsoft.VisualBasic.Chr(25) ' For EM (End of Medium)
' ^^ if you know the ASCII Char Code.
' Use Microsoft.VisualBasic.ChrW() for Unicode (unsure of that)
Public Const vbCharQM As Char = "?"c
Public Const vbComma As Char = ","c
Public Const vbDot As Char = "."c
' or
Public Const vbCharQM2 As Char = CChar("?")
' ^^ if you can actually write the char as String in the Compiler IDE
End Module
Then use the constants identifier anywhere in your project like any VB constant string, but, they are of type Char of course (To combine them with String, you'll have to use .ToString())
Public Sub TestConstChar()
MessageBox.Show("[" + vbEMC.ToString() + "]")
' But hey ! What's the purpose of using End of Medium Char ?
End sub
Note that you have Environment.NewLine that automatically returns the valid Line Feed, or Carriage Return/Line Feed, or only Carriage Return, or even another control Char/String/Stream that is on use on your Operating System.
Based on the Environment.NewLine example, you can also define a (wandering) Class
Public Class MyConstChars
Public Shared ReadOnly Property Tab() As Char
Get
Return Microsoft.VisualBasic.ControlChars.Tab
End Get
End Property
' ...
End Class
' And use it anywhere like myString = "1" + MyConstChars.Tab.ToString() + "One"
This approach allows you to have more control over the actual value of the static/shared Property, like with Environment.NewLine, and allows your Class to propose much more options (Members) than a simple Constant. However, writing the LambdaClassName.LambdaClassProperty isn't very intuitive I reckon.
One another way to ease coding by using constant tags/identifiers in the IDE is to define Code Templates. A code template (piece of code) can be defined in the options of your IDE. You may already know what it is about : you type a keyword, then the IDE replace that keyword with one block of code (that you use often enough to require that shortcut) That's what is happening when you redefines (Overrides) a .ToString() Function in classes.
' I have for example one code template keyword...
PlaceholderChecker
' ...that generates the following Code :
#If IsDebugMode Then
''' <summary>
''' Placeholder Routine to check wether ALL Class Components are included in Solution.
''' </summary>
Private Shared Sub PlaceholderChecker()
p_ClassVariableName_ClassPartialSuffix = True
End Sub
#End If
In some cases, you don't have to define constants - or have to write more complex code - to get where you want.
Related
Casting in Apex seems like Black Magic to me. I don't get when should we make an explicit cast, and when it can be implicit. Like:
Recipe.apxc
public virtual class Recipe{
public string nome;
protected string instructions;
private String source = 'Granny';
public Recipe() {}
public Recipe(String inpNome, String inpInstrucoes) {
nome = inpNome;
instructions = inpInstrucoes;
}
public void printDescription(){
system.debug('Name: ' + nome + ', Instructions: ' + instructions);
return;
}
}
DrinkRecipe.apxc
public class DrinkRecipe extends Recipe{
public String nome = 'Luso';
private String glassType;
public DrinkRecipe(String inpNome, String inpInstrucoes){
super(inpNome, inpInstrucoes);
}
}
in the annonymous window
DrinkRecipe dr = new DrinkRecipe('Whater', 'glu, glu', 'normal');
// why does this work? Shouldn't i always need to cast an object to make it use another constructor, from another class?
Recipe r1 = dr;
system.debug(r1.nome);
// I thought explicit casting like this would be the only way
Recipe r2 = (Recipe) dr;
system.debug(r2.nome);
Thanks
In general, Apex requires you to explicitly convert one data type to another. For example, a variable of the Integer data type cannot be implicitly converted to a String. You must use the string.format method. However, a few data types can be implicitly converted, without using a method.
Numbers form a hierarchy of types. Variables of lower numeric types can always be assigned to higher types without explicit conversion. The following is the hierarchy for numbers, from lowest to highest:
Integer
Long
Double
Decimal
Note
Once a value has been passed from a number of a lower type to a number of a higher type, the value is converted to the higher type of number.
In addition to numbers, other data types can be implicitly converted. The following rules apply:
IDs can always be assigned to Strings.
Strings can be assigned to IDs. However, at runtime, the value is checked to ensure that it is a legitimate ID. If it is not, a runtime exception is thrown.
The instanceOf keyword can always be used to test whether a string is an ID.
I am storing some program values in my Web.config file and would like to use them in my Code.
When i try to set the value like this.
Private Const Security As String = ConfigurationManager.AppSettings("jwtKey")
i get the error Constant expression is required. Is there a way to make this work or do i have to assign the value to each function in my controller which needs access to this constant.
An option is to use the ReadOnly attribute:
Private ReadOnly Security As String = ConfigurationManager.AppSettings("jwtKey")
From the MSDN article:
Specifies that a variable or property can be read but not written.
Just what you are describing, assign a value to a variable but do not allow it to be changed.
This what a constructor is for
Class MyController
Private Const Security As String
Public Sub New
Security = ConfigurationManager.AppSettings("jwtKey")
End Sub
If you're using DI, you could pass all the relevant options in as a single object
I want to format any numeric type using a method call like so:
Option Infer On
Option Strict Off
Imports System.Runtime.CompilerServices
Namespace GPR
Module GPRExtensions
<Extension()>
Public Function ToGPRFormattedString(value) As String
' Use VB's dynamic dispatch to assume that value is numeric
Dim d As Double = CDbl(value)
Dim s = d.ToString("N3")
Dim dynamicValue = value.ToString("N3")
Return dynamicValue
End Function
End Module
End Namespace
Now, from various discussions around the web (VB.Net equivalent for C# 'dynamic' with Option Strict On, Dynamic Keyword equivalent in VB.Net?), I would think that this code would work when passed a numeric type (double, Decimal, int, etc). It doesn't, as you can see in the screenshot:
I can explicitly convert the argument to a double and then .ToString("N3") works, but just calling it on the supposedly-dynamic value argument fails.
However, I can do it in C# with the following code (using LINQPad). (Note, the compiler won't let you use a dynamic parameter in an extension method, so maybe that is part of the problem.)
void Main()
{
Console.WriteLine (1.ToGPRFormattedString());
}
internal static class GPRExtensions
{
public static string ToGPRFormattedString(this object o)
{
// Use VB's dynamic dispatch to assume that value is numeric
var value = o as dynamic;
double d = Convert.ToDouble(value);
var s = d.ToString("N3").Dump("double tostring");
var dynamicValue = value.ToString("N3");
return dynamicValue;
}
}
So what gives? Is there a way in VB to call a method dynamically on an argument to a function without using reflection?
To explicitly answer "Is there a way in VB to call a method dynamically on an argument to a function without using reflection?":
EDIT: I've now reviewed some IL disassembly (via LinqPad) and compared it to the code of CallByName (via Reflector) and using CallByName uses the same amount of Reflection as normal, Option Strict Off late binding.
So, the complete answer is: You can do this with Option Strict Off for all Object references, except where the method you're trying exists on Object itself, where you can use CallByName to get the same effect (and, in fact, that doesn't need Option Strict Off).
Dim dynamicValue = CallByName(value, "ToString", CallType.Method, "N3")
NB This is not actually the equivalent to the late binding call, which must cater for the possibility that the "method" is actually a(n indexed) property, so it actually calls the equivalent of:
Dim dynamicValue = CallByName(value, "ToString", CallType.Get, "N3")
for other methods, like Double.CompareTo.
Details
Your problem here is that Object.ToString() exists and so your code is not attempting any dynamic dispatch, but rather an array index lookup on the default String.Chars property of the String result from that value.ToString() call.
You can confirm this is what is happening at compile time by trying value.ToString(1,2), which you would prefer to attempt a runtime lookup for a two parameter ToString, but in fact fails with
Too many arguments to 'Public ReadOnly Default Property Chars(index As Integer) As Char'
at compile time.
You can similarly confirm all other non-Shared Object methods are called directly with callvirt, relying upon Overrides where available, not dynamic dispatch with calls to the Microsoft.VisualBasic.CompilerServices.NewLateBinding namespace, if you review the compiled code in IL.
You are using a lot of implicit typing, and the compiler doesn't appear to be assigning the type System.Dynamic to the variables you want to be dynamic.
You could try something like:
Option Infer On
Option Strict Off
Imports System.Runtime.CompilerServices
Namespace GPR
Module GPRExtensions
<Extension()>
Public Function ToGPRFormattedString(value as System.Dynamic) As String
' Use VB's dynamic dispatch to assume that value is numeric
Dim d As Double = CDbl(value)
Dim s = d.ToString("N3")
Dim dynamicValue as System.Dynamic = value.ToString("N3")
Return dynamicValue
End Function
End Module
End Namespace
Option Infer On
Option Strict Off
Imports System.Runtime.CompilerServices
Namespace GPR
Module GPRExtensions
<Extension()>
Public Function ToGPRFormattedString(value) As String
Dim dynamicValue = FormatNumber(CDbl(value), 3)
Return dynamicValue
End Function
End Module
End Namespace
I am using a custom class to pass data between methods. One of the primary functions is image handling so I have an image path and a custom thumb path as properties of my class. I want to use the methods included with the System.IO.Path class as part of the properties, but I can't seem to do it this way.
I know how to get this to work by using a string type instead of System.IO.Path as a type so I don't need anyone to tell me how to do it that way. I just think that being able to declare my ImagePath as System.IO.Path would be so much easier because I can use the Path methods on my ImagePath property. I must be missing some understanding about declaring types and I'm hoping I can learn from this question.
How the class is defined:
Public Class myClass
'structured information which will be passed to a replicator
Public Property ID As Integer
Public Property ImagePath As System.IO.Path '<== this doesn't work
Public Property ThumbPath As System.IO.Path '<== this doesn't work
Public Property GroupID As Byte
Public Property SystemID As Byte
Public Property Comment As String
'Other properties
End Class
How I would like to use this class:
Public Function myReplicatorFunc(myObj as myClass)
Dim myTempPath as string
Dim myDBObj as myDBConnection
'handle database connections
myTempPath = myObj.ImagePath.GetDirectoryName() & "\" _
myDBObj.GetIntID.toString() & "\" _
myObj.ImagePath.GetExtension()
My.Computer.FileSystem.RenameFile(myObj.ThumbPath.toString, myTempPath)
'Other file movements for replication etc
End Function
Why can't I declare a property as a System.IO.Path class? If the answer is just "NO" for some reason (please explain why) then how can I use the System.IO.Path methods as extensions to my properties without re-writing as a custom class with exact copies of the same methods?
You cannot declare an instance of System.IO.Path because it's a static class - it cannot be instantiated. Think of it as simply a grouping of path-related global functions under a System.IO.Path namespace. (The real namespace is just System.IO but because Path is a static class, functionally it really behaves as if was just a namespace for a bunch of related global functions.)
Your ImagePath property needs to be string and you just need to pass it to Path functions when you need that logic. This is somewhat unfortunate.
As an alternative, you can create a new class (sorry, C# code; I'm not a VB.NET expert):
using System;
using System.IO;
// import namespaces as necessary
public class Filename
{
private string m_sFilename;
public Filename ( string sFilename )
{
m_sFilename = sFilename;
}
public string FullName
{
get
{
return ( m_sFilename );
}
set
{
m_sFilename = value;
}
}
public string FolderName
{
get
{
return ( Path.GetDirectoryName ( m_sFilename ) );
}
}
// Add more properties / methods
...
}
Once you have this class, you can write:
private Filename m_oImagePath = null;
I did pretty much the same in my project because having a specific type for folder / file paths makes it easier to update logic related to operations on path names.
Why not use DirectoryInfo like:
Public Property ImagePath As System.IO.DirectoryInfo
Public Property ThumbPath As System.IO.DirectoryInfo
Is there a fast way in VB.NET to take a 32-bit int and cast to a 32-bit float while preserving the underlying bit structure? BitConverter will do this, but I'd like to cast it directly without involving byte arrays.
Damn, how could I possibly forget about The C-style Union?
<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Explicit)> _
Public Structure IntFloatUnion
<Runtime.InteropServices.FieldOffset(0)> Public i As Integer
<Runtime.InteropServices.FieldOffset(0)> Public f As Single
End Structure
Sub Main()
Dim u As IntFloatUnion
u.i = 42
Console.WriteLine(u.f)
Console.ReadLine()
End Sub
Well, how about writing a helper function in C# similar to one shown here:
public static class FancyConverter
{
public static unsafe float FloatFromBytes(int i)
{
return *((float*)(void*)(&i));
}
}
This can be compiled to a separate dll and referenced from the VB project.