Files
eiffel-org/documentation/23.09/solutions/dotnet/eiffel-net-language/eiffel-net-integration.wiki
eiffel-org a6559e5b4a uired
Updated wikipage Eiffel for .NET Integration.
	(Signed-off-by:jocelyn).

git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@2418 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
2023-10-02 09:59:58 +00:00

172 lines
9.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[[Property:modification_date|Mon, 02 Oct 2023 09:59:58 GMT]]
[[Property:publication_date|Wed, 27 Sep 2023 19:33:07 GMT]]
[[Property:title|Eiffel for .NET Integration]]
[[Property:weight|3]]
[[Property:uuid|fe8a6a7d-4590-0db2-d59a-307082b18ecc]]
==Differences between Eiffel and Eiffel for .NET==
===Limitation of Eiffel for .NET in version 23.09===
Most of the Eiffel mechanisms are supported in 23.09.
Eiffel for .NET supports:
* Multiple Inheritance
* Design By Contract
* Exception handling
* Genericity
* Covariance
* Compilation of any existing Eiffel libraries as long as it does not include C externals that call into the Eiffel Software C runtime
However, there are a few limitations that are described later in this documentation.
===Added to Eiffel and Eiffel for .NET===
The following syntax can be used to declare .NET custom attributes on Eiffel entities (features and classes):
<code>
empty: BOOLEAN
note
description: "Is Current empty?"
metadata: create {OBSOLETE_ATTRIBUTE}.make ("Use `is_empty' instead") end
obsolete
"Use is_empty instead"
do
Result := is_empty
end
</code>
The previous example shows the declaration of the obsolete feature <code> empty </code> . The custom attribute defined by <code>OBSOLETE_ATTRIBUTE</code> is used to ensure that any consumer of the resulting assembly will see the feature as being obsolete. The custom attribute is defined in the <code>note</code> clause <code>metadata</code>. The definition consists of a creation expression that creates the custom attribute with the right parameters.
Using the <code>metadata</code> tag is the most general way of applying a custom attribute. There are however some variations that are explained below:
*<code>metadata</code>: most general way, it applies a custom attribute to both the class and interface generated by the Eiffel compiler.
*<code>class_metadata</code>: applies only to the class generated by the Eiffel compiler (mostly for advanced users).
*<code>interface_metadata</code>: applies only to the interface generated by the Eiffel compiler (mostly for advanced users).
*<code>property_metadata</code>: applies a custom attribute to the associated property generated by the Eiffel compiler for a query.
*<code>assembly_metadata</code>: applies a custom attribute for the current assembly. It only works when present in the Eiffel system root class <code>note</code> clause.
==Differences between Eiffel for .NET and .NET==
===Covariance===
The CLR (Common Language Runtime) does not support [[ET: Inheritance#Covariance and anchored declarations|covariance]] due to a different view of type safety (the issue is known known as a polymorphic [[ET: Inheritance#Catcalls|catcall]] in Eiffel). Catcalls are possible (although very rare) in Eiffel but not in .NET.
Eiffel for .NET implements a safe variant of covariance that will always perform a check on the types to avoid a catcall. So when a catcall is going to be performed a `Invalid Cast Exception` will be raised by the CLR instead of an unexpected behavior as is the default behavior in classic Eiffel (i.e., the behavior without catcall detection explicitly enabled).
Another advantage of Eiffel for .NET's implementation of covariance is that it can be easily understood by CLS-compliant consumer tools. These tools will actually benefit from the Eiffel for .NET covariance.
===Handling Eiffel and .NET genericity===
As noted above, Eiffel for .NET fully supports the powerful genericity mechanism of the Eiffel language. The interface with .NET's own genericity mechanism is, however, not complete in version 23.09. Specifically:
* Generic classes in Eiffel will not yield generic classes in .NET. Instead, each generic derivation of a given Eiffel class will yield a different .NET class. So if we have a generic Eiffel class <code>LIST [G]</code>, the type <code>LIST [ANY]</code> will yield a .NET class <code>LIST_ANY</code>, and the type <code>LIST [INTEGER]</code> will yield a class <code>LIST_Int32</code> .
* If you want to use a generic .NET class (for example in C#), you have to use special techniques as described next.
===Using generic .NET classes through a facade===
Currently, Eiffel does not support consuming generics from C# classes. This tutorial demonstrates a workaround for this limitation by creating a Facade for a `List<string>` in C#
====Creating a facade for the List type====
A Facade simplifies access to complex components. In this case, we will create a Facade to manage a list of strings. The Facade will encapsulate the list's functionality and expose a more straightforward interface. Here's how you can do it:
<code lang="cs">
using System.Collections;
namespace ListOfString;
/// <summary>
/// Facade for a List<string> that encapsulates the list's functionality and exposes a few methods
/// </summary>
public class ListOfString
{
private List<string> _list;
public ListOfString()
{
_list = new List<string>();
}
public void Add(string item)
{
_list.Add(item);
}
public bool Contains(string item)
{
return _list.Contains(item);
}
public void Remove(string item)
{
_list.Remove(item);
}
public IList GetList()
{
return _list.ToList();
}
}
</code>
====Creating a C# library====
To consume the Facade in Eiffel, we need to create a C# library. I recommend following the tutorial on creating a class library with C# and .NET on Microsofts official site. You can access it [https://learn.microsoft.com/en-us/dotnet/core/tutorials/library-with-visual-studio?pivots=dotnet-7-0 here]. This tutorial guides you through the process of creating a class library using C# and .NET.
====Consuming the C# library from Eiffel====
Finally, we need to consume the C# library from Eiffel.
Open the Eiffel configuration file (.ecf) of your project and add the following entry
<code><assembly name="ListOfString" location="$PATH_CS_LIB\ListOfString.dll"/></code>
====Conclusion====
By creating a Facade for a `List<string>` in C#, we can effectively consume C# generic features in Eiffel.
This approach can be extended to other generic types as well.
===Enum types===
Eiffel for .NET supports .NET enum types implicitly. From the point of view of Eiffel, they are just considered as expanded classes. The only difference is in the code generation. Eiffel for .NET cannot declare new enum types yet.
===ByRef===
Eiffel does not have the notion of `byref` argument passing. At the moment, Eiffel for .NET cannot call nor can it redefine a feature that has a byref argument.
==Eiffel compatibility with .NETCore 6.0 and above ==
=== Type with "init" only setters===
Eiffel currently does not support the special `init` property that is only initialized in a block of code as part of the object initialization. More details can be found in the [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/init C# 9.0 proposal]
====Workaround====
A potential workaround is to create a C# library that uses a Factory pattern to build the required instance.
===Executing Eiffel .NET Core applications ===
At the moment, the EiffelStudio '''debugger has no support''' Eiffel .NET Core.
It is, however, possible to execute most of the Eiffel .NET Core application from the IDE using the `Run` command. The execution will be outside EiffelStudio.
{{note|The generated executable can not be executed by itself and requires to be launched using the `dotnet` tool from the command line. Using the the syntax: `dotnet <app_name>` or `dotnet run <app_name>`.}}
{{tip|In addition, it is possible that an application requires additional setting (for example web APIs application), in this case the `dotnet run` tool can use a specific profile using the syntax `--launch-profile <NAME>`.}}
{{info|Read more about the `dotnet` tool, and especially the `run` command at [https://learn.microsoft.com/fr-fr/dotnet/core/tools/dotnet-run] .}}
To help the user, the EiffelStudio compiler also generates (in W_code or F_code directories) a C# wrapper project. See the `wrapper_*.cs` and `wrapper_*.csproj` files.
This "wrapper" project will be useful for specific execution, but also [[#Publishing|publishing]] the executable, or even '''debugging''' using VisualStudio. See the next sections for more information.
====Publishing====
This '''wrapper''' project is helpful to '''publish''' the executable to the current or other platforms, and have an executable that does not require the `dotnet` command. It is also possible to include all dependencies (i.e: self contained) to ease deployment on machine without any dotnet runtime installed.
{{note: use the `dotnet publish` tool on the generated C# wrapper project. See the documentation about `dotnet publish` at [https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-publish] .}}
====Debugging in VisualStudio====
Even if EiffelStudio does not provide any support for debugging Eiffel .NETCore directly from the IDE.
It is possible to use VisualStudio to debug the generated Eiffel .NETcore application thanks to the wrapper C# project.
A solution is to use the C# wrapper project generated by the Eiffel compiler (in W_code or F_code directory) within VisualStudio.
* Open the C# `.csproj` file with VisualStudio (it includes the associated Eiffel output dll or exe)
* Configure the Debugging profile
* Launch the execution with VisualStudio, and debug.
====Limitations====
In the current version, the EiffelStudio compiler will always generate a Microsoft.NET.Sdk C# wrapper project. But this is not always the expected type SDKs.
For instance when using ASP.NETCore, it is expected to use `Microsoft.NET.Sdk.Web`.
In such case, the generated `.csproj` file needs to be manually modified to set the expected SDK, and also the various package dependencies.
This allows the application to be run and, if necessary, debugged using VisualStudio.