I encounter what I believe to be a bug and I was just wondering if this is already known as a issue or if this is not a issue and why.
The problem related to Read Only Properties on a Type when compiling with the VB.Net Compiler in Visual Studio 2008.
Follows are the class definitions and a small C# program which will not compile. (And is correct in not compiling IMHO because the property being set in the Delegate is Read-only)
public interface ITest
{
bool PrivateBool { get; }
}
public class TestClass : ITest
{
bool privateBool = false;
public bool PrivateBool
{
get
{
return privateBool;
}
}
bool publicBool = false;
public bool PublicBool
{
get { return publicBool; }
set { publicBool = value; }
}
}
class Program
{
static void Main(string[] args)
{
TestClass tc = new TestClass();
//Compile Error
//tc.PrivateBool = false;
//Compile Error
//Action act = new Action(delegate()
//{
// tc.PrivateBool = false;
//});
//Action<TestClass> test = new Action<TestClass>(delegate(TestClass tcc)
//{
// tcc.PrivateBool = false;
//});
//Compile Time Error
//Action<TestClass> test = new Action<TestClass>( tz=> tz.PrivateBool = false);
//Compile Time Error
//Action test = new Action(tc.PrivateBool = false);
}
}
In VB.Net However this is a larger issue… the program will compile and execute with no exception. But the property is not set.
This was a nightmare to catch in the debugger at Run time and we feel that the compiler should have caught that we are assigning to a ready only property just as the CSharp compiler alerts you when compiling.
Module Module1
Sub Main()
Dim tc As New TestClass()
Dim setP = New Action(Of TestClass)(Function(d As TestClass) _
d.PrivateBool = False _
)
setP.Invoke(tc)
End Sub
End Module
Can anyone explain if this is correct logic and why?
I assume that someone will respond that the job of the compiler was fulfilled by examining the parameter type to the delegate and that the delegate was typed to accept that parameter just as it should when parsing a Method Body or a Function Body.
My rebuttal to this would be that the compiler DOES throw an error when that property is attempted to be set from within a method but not the delegate. Delegates should be parsed the same as a Method.
Is the C# compiler over extending itself? I think not. My experience is that this is a bug in the vb.net compiler and should be fixed by a patch to the IDE.
Last but surely not least what occurs when the Invoke happens?
The delegate surely does not use reflection to set the property automagically so I assume the CLR sees the read-only qualifier and a NOOP gets executed. Is that actually what occurs or is the behavior undefined?
Thank you for your time!
In VB.NET 2008, there are no statement lambdas. All lambdas are functions. They return a value, not perform an action.
Your VB lambda simply compares d.PrivateBool and False and returns the result of the comparison.
This is not a bug and by design. It is therefore advisable to avoid assigning VB.NET 2008's lambdas to an Action, this is highly confusing for an unprepared person.
Statement lambdas appeared in VB.NET 2010.
Related
Say, a test needs a parameter that is only known when the tests are about to run.
#ExtendWith(MyParameterExtension.class)
public class Test {
protected final MyParameter p;
public Test(MyParameter p) {}
#Test
public void test() { assertSuccess(TestedCode.doComplexThing(p)); }
}
Only before the tests are executed, the specific contents of MyParameter instance can be determined. So I can have a resolver extension that simple pastes that parameter value where needed:
class MyParameterExtension implements ParameterResolver {
private final MyParameter myParameter;
public MyParameterExtension(MyParameter p) {
myParameter = p;
}
#Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
return (parameterContext.getParameter().getType() == MyParameter.class);
}
#Override
public MyParameter resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
return myParameter;
}
}
I run the tests by starting Junit5 from my own code. That's when I can determine what the corresponding parameter values are. Let's say these parameters drive the behavior of the tests, and a user can specify (i.e., over a CLI) the values that a run should use.
How do I register the extension with the test run, as I'm about to commence it?
void launchSuite(List<DiscoverySelector> selectors, Object something) {
// The input to this are all the necessary selectors.
LauncherDiscoveryRequest ldr = LauncherDiscoveryRequestBuilder.request()
.selectors(selectors).build();
Launcher launcher = LauncherFactory.create();
TestPlan plan = launcher.discover(ldr);
MyParameter myParameter = new MyParameter(something);
MyParameterExtension ext = new MyParameterExtension(myParameter);
// $TODO: how do I register my extension with the test run
// before starting it?
launcher.execute(plan);
}
Auto-registering extensions doesn't help me (how would that process know the value of MyParameter)
Using #RegisterExtension in the test code doesn't help me (A static block in the test code won't know the proper input for constructing instances of MyParameter)
Looking at the mechanics of launching the test, I don't see anything that lets me register those extensions in advance.
I considered using a ThreadLocal field in an extension registered statically but AFAIU, this won't (reliably) work because JUnit may create its own threads at least in certain cases.
I considered sticking the value of MyParameter in the "extension context", but I don't see a way to grab a hold of that before the test execution starts either. The root context is created in JupiterEngineDescriptor that is, if nothing else, all internal API.
The obvious solution is to stick the parameter in a static field somewhere, but that would preclude me from running tests with different parameters in parallel, unless I resort to loading tests into isolated class loaders, which sounds too cumbersome for something that I believe should be simpler. After all, all of the contexts of a test run are otherwise fully isolated.
What I'm ultimately trying to do, at then, as to make something like this possible:
// ...
new Thread(()->launchSuite(selectors, "assume Earth gravity")).start();
new Thread(()->launchSuite(selectors, "assume Mars gravity")).start();
So what's are the reasonable ways to wire something this together?
Let's start with the one thing that does not work: Using the launcher API.
The launcher API is a platform feature, whereas extensions are Jupiter-related. That's why there is no mechanism to register an extension in the API.
What should work, though, is #RegisterExtension - although you claim it would not. As the documentation shows it is not restricted to static fields. Therefore, whatever you do here:
MyParameter myParameter = new MyParameter(something);
MyParameterExtension ext = new MyParameterExtension(myParameter);
could be done in a static method to instantiate an extension during runtime:
public class Test {
private static MyParameterExtension createExtension() {
MyParameter myParameter = new MyParameter(something);
return new MyParameterExtension(myParameter);
}
#RegisterExtension
private MyParameterExtension my = createExtension();
#Test
public void test(MyParameter p) {
assertSuccess(TestedCode.doComplexThing(p));
}
}
If that doesn't work in your case, some information is missing from your problem statement IMO.
Update
If your extension creation code requires parameters that can only be determined at launch time, you have the option of adding configuration parameters to the discovery request:
LauncherDiscoveryRequest ldr = LauncherDiscoveryRequestBuilder.request()
.configurationParameter("selectors", "assume Earth gravity")
.selectors(selectors).build();
This parameter can then be retrieved within the extension:
class MyParameterExtension implements ParameterResolver {
...
#Override
public MyParameter resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
var selectors = extensionContext.getConfigurationParameter("selectors").orElse("");
return new MyParameter(selectors);
}
}
I'm working on a project which is written in VB.NET. The project has several Structures which used to have writable fields. I replaced all of those fields with read-only properties, and wrote functions for creating a copy of a structure that has one of its properties changed.
I was assuming that every part of the code that attempted to write to one of these properties would become an error, and then I could simply fix all the errors by making the code call the new functions. To my dismay, it turns out that if a ReadOnly property is accidentally passed into a ByRef parameter of a function, the compiler accepts this with no warning, and the value that's assigned is silently discarded!
Here's an example:
Structure Point
Public ReadOnly Property X As Integer
Public ReadOnly Property Y As Integer
End Structure
Module Module1
Sub IncreaseByOne(ByRef x As Integer)
x = x + 1
End Sub
Sub Main()
Dim point As New Point
IncreaseByOne(point.X)
Console.WriteLine($"point.X is {point.X}")
End Sub
End Module
I was hoping that the line IncreaseByOne(point.X) would throw an error, or at least a warning, since point.X is read-only and it doesn't make sense to pass it by reference. Instead, the code compiles with no warnings, and the value assigned to x inside of IncreaseByOne is silently discarded, and the program prints point.X is 0.
How can I detect all of the places in my code where a read-only property is passed into a function that takes it by reference? The only way I can think of is to go through every read-only property that I have, find all places where that property is used as a parameter, and look to see if that parameter is ByRef. That'll be very time-consuming, but if there's no other solution, then that's what I'll do.
I'm using Visual Studio 2019. I'm open to installing new software in order to do this.
That's really interesting. The VB.NET Compiler really tries to make a property look like a variable. Even if I explicitly declare the property as
Structure Point
Dim _x As Integer
ReadOnly Property X() As Integer
Get
Return _x
End Get
End Property
End Structure
The code compiles and executes as before. If the property setter is added, it even works correctly!
Structure Point
Dim _x As Integer
Property X() As Integer
Get
Return _x
End Get
Set(value As Integer)
_x = value
End Set
End Property
End Structure
With the above change, the program correctly prints 1.
Looking at the generated IL, we can see why:
IL_0009: ldloca.s point
IL_000b: call instance int32 VisualBasicConsoleTest.Point::get_X()
IL_0010: stloc.1 // Store returned value in local variable
IL_0011: ldloca.s // load address of that local variable (and pass to function call)
IL_0013: call void VisualBasicConsoleTest.Program::IncreaseByOne(int32&)
IL_0018: nop
IL_0019: ldloca.s point
IL_001b: ldloc.1 // Load contents of local variable again
IL_001c: call instance void VisualBasicConsoleTest.Point::set_X(int32) // and call setter
Even though we expect an error because a property is not a value (and a byref requires a value), the compiler fakes what we might have intended: He actually generates a call to the getter, stores the value on the stack, passes a reference to the stack(!) to the called function and then calls the setter with that value.
This works in this simple scenario, but I agree with the commenters above, this might be very confusing when looking at it in detail. If the property is actually a computed property, the outcome is just arbitrary (try implementing the getter as Return _x + 1...)
C# would throw an error here, because a property is not a value and hence cannot be used as an out or ref parameter.
As Craig suggested in this answer, I went ahead and wrote a custom analyzer to detect when this occurs. Now, I can simply do Analyze / Run Code Analysis / On Solution, and every place that the described problem occurs gets marked with a warning such as "The property 'point.X' is read-only and should not be passed by reference."
The entire analyzer is available on GitHub. I've copied the important part below:
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.SimpleArgument);
}
private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
{
SimpleArgumentSyntax node = (SimpleArgumentSyntax)context.Node;
SemanticModel semanticModel = context.SemanticModel;
if (!IsByRef(node, semanticModel))
return;
(bool isReadOnly, string symbolType) = IsReadOnly(node, semanticModel);
if (isReadOnly)
{
Diagnostic diagnostic = Diagnostic.Create(
Rule,
node.Expression.GetLocation(),
symbolType,
node.Expression.GetText());
context.ReportDiagnostic(diagnostic);
}
}
/// <summary>
/// Determine if the given argument is passed by reference.
/// </summary>
private static bool IsByRef(SimpleArgumentSyntax node, SemanticModel semanticModel)
{
ArgumentListSyntax argumentList = (ArgumentListSyntax)node.Parent;
if (argumentList.Parent is InvocationExpressionSyntax invocation)
{
SymbolInfo functionInfo = semanticModel.GetSymbolInfo(invocation.Expression);
if (functionInfo.Symbol is IMethodSymbol method)
{
IParameterSymbol thisParameter = null;
if (node.IsNamed)
{
thisParameter = method.Parameters.FirstOrDefault(parameter =>
parameter.Name == node.NameColonEquals.Name.ToString());
}
else
{
int thisArgumentIndex = argumentList.Arguments.IndexOf(node);
if (thisArgumentIndex < method.Parameters.Length)
thisParameter = method.Parameters[thisArgumentIndex];
}
// If we couldn't find the parameter for some reason, the
// best we can do is just accept it.
if (thisParameter == null)
return false;
RefKind refKind = thisParameter.RefKind;
if (refKind != RefKind.None && refKind != RefKind.In)
return true;
}
}
return false;
}
/// <summary>
/// Determine if the given argument is a read-only field or property.
/// </summary>
private static (bool isReadOnly, string symbolType) IsReadOnly(SimpleArgumentSyntax node, SemanticModel semanticModel)
{
string symbolType = "field or property";
bool isReadOnly = false;
if (node.Expression is MemberAccessExpressionSyntax memberAccess)
{
SymbolInfo memberInfo = semanticModel.GetSymbolInfo(memberAccess.Name);
if (memberInfo.Symbol is IPropertySymbol propertySymbol && propertySymbol.IsReadOnly)
{
symbolType = "property";
isReadOnly = true;
}
if (memberInfo.Symbol is IFieldSymbol fieldSymbol && fieldSymbol.IsReadOnly)
{
symbolType = "field";
isReadOnly = true;
}
}
return (isReadOnly, symbolType);
}
There isn't a way to catch this with the compiler. Even Option Strict On will allow passing a read-only property to a ByRef argument. This is defined to pass by copy-in/copy-out, and it's surprising to me that the copy-out part will compile even when the Property Set is inaccessible.
If you want to have an automated lint-type check for this, I would imagine that a custom analyzer could find it. I haven't worked with analyzers, so I don't have any specific suggestions for how to write one or set it up.
Otherwise, you're left to a manual check. As was noted in a comment, you can use the "Find All References" command from Visual Studio to help with it, but this will still require a manual review of every read-only property.
Given the new dynamic support in C# 4, is it possible to write a class in such a way that if a method is invoked on an instance and that method is not present, dispatch is passed to another method? This might look something like:
public class Apple : ... {
// ...
private ... MethodMissing(string name, ...) {
if (name == "TurnIntoOrange") {
// do something
}
}
}
dynamic d = new Apple();
d.TurnIntoOrange(); // Not actually defined on Apple; will pass to MethodMissing.
Other languages would call this "method_missing support", under the more general heading of metaprogramming. I'm not sure what C# calls this specifically. But is it possible?
Absolutely. Either implement IDynamicMetaObjectProvider or derive from DynamicObject for a much simpler route. See the DLR documentation for some good examples.
Here's a quick example of DynamicObject:
using System;
using System.Dynamic;
public class MyDynamic : DynamicObject
{
public override bool TryInvokeMember
(InvokeMemberBinder binder,
object[] args,
out object result)
{
Console.WriteLine("I would have invoked: {0}",
binder.Name);
result = "dummy";
return true;
}
public string NormalMethod()
{
Console.WriteLine("In NormalMethod");
return "normal";
}
}
class Test
{
static void Main()
{
dynamic d = new MyDynamic();
Console.WriteLine(d.HelloWorld());
Console.WriteLine(d.NormalMethod());
}
}
<plug>
I have a bigger example of DynamicObject in the 2nd edition of C# in Depth but I haven't yet implemented IDyamicMetaObjectProvider. I'll do so before the book's release, but the early access edition only has the DynamicObject example at the moment. Btw, if you buy it today it's half price - use the code twtr0711. I'll edit this answer later on to remove that bit :)
</plug>
I am using JNA to access a custom DLL which seems to be using the FAR PASCAL Calling Conventions, but the JVM crashes every time i try to access it.
Development Guide of the dll says:
BOOL FAR PASCAL GetIomemVersion(LPSTR);
And Dependency Walker tells me:
_GetIomemVersion#4
public class PebblePrinter {
public interface Iomem extends StdCallLibrary {
boolean _GetIomemVersion(String version);
}
String version;
Iomem INSTANCE;
StdCallFunctionMapper myMapper;
public PebblePrinter() {
HashMap optionMap = new HashMap();
myMapper = new StdCallFunctionMapper();
optionMap.put(Library.OPTION_FUNCTION_MAPPER, myMapper);
INSTANCE = (Iomem)Native.loadLibrary("iomem", Iomem.class,optionMap);
}
public String getIomemVersion(){
INSTANCE._GetIomemVersion(version);
return version;
}
}
With C# code it works well using
[DllImport("iomem.dll", EntryPoint = "_GetIomemVersion#4")]
public static extern bool GetIomemVersion(IntPtr version);
Can you tell me what i am doing wrong?
Thanks in advance!!!
Problem solved,
I've just used the wrong parameter ..
GetIomemVersion needs a Pointer
boolean _GetIomemVersion(Pointer version);
public String getIomemVersion(){
Memory m = new Memory(1024);
Pointer x = m.getPointer(0);
INSTANCE._GetIomemVersion(x);
return x.getString(0);
}
As I develop code, I often want to unit test some of the building blocks of a class even if they are normally private. If my unit tests are inside the project, I can use "Friend" to accomplish this and still keep the functions private for normal use. But I would rather move my NUnit tests into their own separate project(s). How do I achieve the effect I'm looking for?
You can't (easily) test private methods from a different project, but it's quite common to test internal methods (Friend in VB) from a test project using InternalsVisibleToAttribute. This makes Friend members accessible to another assembly.
Apparently this was new in VB 9 although it was available in C# 2... not quite sure why, but this blog post from Bart de Smet gives a quick example.
Note that if your production assembly is signed, your test assembly will need to be signed too, and you'll have to specify the public key in the InternalsVisibleToAttribute arguments. See this Stack Overflow answer for more details.
You can use Reflection to invoke the private methods. There are plenty of samples out there to do this.
From a quick google search: http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx
The basics: (this is pasted from the code project site linked above)
public static object RunStaticMethod(System.Type t, string strMethod,
object [] objParams)
{
BindingFlags eFlags =
BindingFlags.Static | BindingFlags.Public |
BindingFlags.NonPublic;
return RunMethod(t, strMethod,
null, aobjParams, eFlags);
} //end of method
public static object RunInstanceMethod(System.Type t, string strMethod,
object objInstance, object [] aobjParams)
{
BindingFlags eFlags = BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic;
return RunMethod(t, strMethod,
objInstance, aobjParams, eFlags);
} //end of method
private static object RunMethod(System.Type t, string
strMethod, object objInstance, object [] aobjParams, BindingFlags eFlags)
{
MethodInfo m;
try
{
m = t.GetMethod(strMethod, eFlags);
if (m == null)
{
throw new ArgumentException("There is no method '" +
strMethod + "' for type '" + t.ToString() + "'.");
}
object objRet = m.Invoke(objInstance, aobjParams);
return objRet;
}
catch
{
throw;
}
} //end of method