# Unqualified References

Unqualified references are a big source of problems in CTD applications because it's not immediately clear where the variable is declared and they are evaluated dynamically at runtime. The result may be unpredictable. C# and VB.NET do not support any ambiguous reference (being strongly typed and compiled languages), therefore during porting we have to clearly and fully qualify all the unqualified references.

## Fully Unqualified

Fully unqualified references are very hard to translate because in CTD they are resolved at runtime and can address just about anything. For example, the statement "Set nValue = 10" may be written in a global function, or in a class, or in any other place where *nValue* is nowhere to be seen. It's enough that the symbol is either a control or a variable on any top level form and CTD will find it dynamically at runtime. When porting, Ice Porter looks for the unqualified symbol in all top level forms and if it finds it in only one place, it fully qualifies the expression by using the templates static instance declared in the *Application* class.

For example:

```abap
Set dfAge = 20
```

If dfAge is declared in frmPatient, the code ports to:

```csharp
App.frmPatient.dfAge.Number = 20;
```

It's exactly the same as if the assignment was qualified in SAL as

```abap
Set frmPatient.dfAge = 20
```

However, if the same symbol is present in more than one top level form, Ice Porter cannot generate any expression that makes sense and will log an error.

## Class Qualified

Class qualified expressions include a window handle and a class or form template name. When the window handle is *hWndItem* or *hWndForm* or *hWndMDI* and the expression is within the current form or control, Ice Porter is capable of optimizing the expression and generates a direct expression using the *this* keyword. When a class is specified and the handle is not the current form, the generated code converts the window handle to the specified class either using a custom cast, or using a custom *FromHandle* static method, depending on the options that were selected in the Ice Porter project.

For example:

```abap
Set hWnd.CDfNumber.dfAge = 20
```

Is ported to:

```csharp
((CDfNumber)hWnd).Number = 20;
```

Or to:

```csharp
CDfNumber.FromHandle(hWnd).Number = 20;
```

The end result is exactly the same. The *FromHandle* syntax may be considered by some C# developers to be more consistent with the .NET Framework way of converting handles to controls. Other developers may prefer the cast expression because it may be more similar to original SAL code. It's just a matter of taste.

{% hint style="warning" %}
CTD does not check that the specified control derives from the specified class and simply casts the control to the class. This is a common problem in SAL applications and the source of many random crashes in CTD. Ice Porter may be able to identify these mistakes while porting, but in some cases you may end up with an *InvalidCastException* at runtime.
{% endhint %}

## Handle Semi-qualified

Handle semi-qualified expressions are similar to the Class qualified but without the class name. CTD looks for the specified symbol at runtime within the control identified by the window handle. Ice Porter may be able to optimize these expressions if the symbol is declared in only one top level form. When the expression cannot be optimized, the generated code looks like this:

```csharp
SalWindow.Findmember(hWnd, "dfAge").Number = 20;
```

The code above looks for the *dfAge* member within the control identified by *hWnd* at runtime.

## Ambiguous Unqualified References

When Ice Porter cannot qualify an unqualified expression because the symbol is present in multiple locations, it resorts to using a special runtime evaluation function that is capable of looking up the symbol at runtime.

For example:

```abap
Set hWnd.sName = "PPJ"
```

When *sName* is present in more than one top level form, therefore it's impossible to generate a qualified expression, we generate the following expression:

```csharp
SalWindow.FindMember(hWnd, "sName").String = "PPJ";
```

At runtime, the method *SalWindow\.FindMember()* uses a particularly fast reflection code to read/write the member dynamically. However, we strongly suggest to remove all the ambiguous unqualified expressions when possible.
