Skip to content

Commit

Permalink
jekyll build from Action e54d2b9
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeyfv committed Oct 15, 2024
0 parents commit acf0d55
Show file tree
Hide file tree
Showing 175 changed files with 12,505 additions and 0 deletions.
Empty file added .nojekyll
Empty file.
418 changes: 418 additions & 0 deletions 2022/01/31/insidious-enum-in-dotnet.html

Large diffs are not rendered by default.

300 changes: 300 additions & 0 deletions 2022/05/01/fsharp-01.html

Large diffs are not rendered by default.

359 changes: 359 additions & 0 deletions 2022/05/08/fsharp-02.html

Large diffs are not rendered by default.

472 changes: 472 additions & 0 deletions 2022/07/14/how-to-create-blog.html

Large diffs are not rendered by default.

320 changes: 320 additions & 0 deletions 2023/01/31/react-html-annotations.html

Large diffs are not rendered by default.

394 changes: 394 additions & 0 deletions 2023/02/25/ef-inheritance.html

Large diffs are not rendered by default.

341 changes: 341 additions & 0 deletions 2023/06/05/understanding-ddd-01.html

Large diffs are not rendered by default.

676 changes: 676 additions & 0 deletions 2023/07/30/secure-app-with-keycloak.html

Large diffs are not rendered by default.

172 changes: 172 additions & 0 deletions 2023/08/10/top-level-statements.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" sizes="16x16 32x32 48x48" href="/assets/favicon/favicon.ico">
<link rel="apple-touch-icon" href="/assets/favicon/apple-touch-icon.png"><!-- Begin Jekyll SEO tag v2.7.1 -->
<title>How to call Program.Main method if you’re using top-level statements | alexeyfv</title>
<meta name="generator" content="Jekyll v4.2.1" />
<meta property="og:title" content="How to call Program.Main method if you’re using top-level statements" />
<meta name="author" content="© 2024 Alexey Fedorov" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="Lately, I’ve been writing a lot of services that use top-level statements. The code with this kind of syntax sugar simplifies the Main method and improves readability. However, on the other hand, it makes it more difficult to create integration tests for the services. There isn’t simply way to call the Main method and pass the necessary arguments." />
<meta property="og:description" content="Lately, I’ve been writing a lot of services that use top-level statements. The code with this kind of syntax sugar simplifies the Main method and improves readability. However, on the other hand, it makes it more difficult to create integration tests for the services. There isn’t simply way to call the Main method and pass the necessary arguments." />
<link rel="canonical" href="http://www.alexeyfv.xyz//2023/08/10/top-level-statements.html" />
<meta property="og:url" content="http://www.alexeyfv.xyz//2023/08/10/top-level-statements.html" />
<meta property="og:site_name" content="alexeyfv" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2023-08-10T00:00:00+00:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="How to call Program.Main method if you’re using top-level statements" />
<script type="application/ld+json">
{"author":{"@type":"Person","name":"© 2024 Alexey Fedorov"},"description":"Lately, I’ve been writing a lot of services that use top-level statements. The code with this kind of syntax sugar simplifies the Main method and improves readability. However, on the other hand, it makes it more difficult to create integration tests for the services. There isn’t simply way to call the Main method and pass the necessary arguments.","@type":"BlogPosting","headline":"How to call Program.Main method if you’re using top-level statements","dateModified":"2023-08-10T00:00:00+00:00","datePublished":"2023-08-10T00:00:00+00:00","mainEntityOfPage":{"@type":"WebPage","@id":"http://www.alexeyfv.xyz//2023/08/10/top-level-statements.html"},"url":"http://www.alexeyfv.xyz//2023/08/10/top-level-statements.html","@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="/assets/css/style.css"><link type="application/atom+xml" rel="alternate" href="http://www.alexeyfv.xyz//feed.xml" title="alexeyfv" />
</head><body><header class="site-header">

<div class="wrapper"><a class="site-title" rel="author" href="/">alexeyfv</a><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger">
<span class="menu-icon">
<svg viewBox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"/>
</svg>
</span>
</label>

<div class="trigger"><a class="page-link" href="/tags/">Tags</a><a class="page-link" href="/cv/">CV</a><a class="page-link" href="/about/">About</a></div>
</nav></div>
</header>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<article
class="post h-entry"
itemscope
itemtype="http://schema.org/BlogPosting"
>
<link rel="stylesheet" href="/static/glide/css/glide.core.min.css" />
<link rel="stylesheet" href="/static/glide/css/glide.theme.min.css" />
<script type="text/javascript" src="/static/glide/glide.min.js"></script>
<link href="/static/syntax-highlighting.css" rel="stylesheet" />
<link href="/static/image.css" rel="stylesheet" />
<script>
function initGlideCarousel() {
var sliders = document.querySelectorAll(".glide");
const conf = {};
sliders.forEach((item) => {
new Glide(item, conf).mount();
});
}
document.addEventListener("DOMContentLoaded", initGlideCarousel);
</script>
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">
How to call Program.Main method if you&#39;re using top-level statements
</h1>
<p class="post-meta"><time
class="dt-published"
datetime="2023-08-10T00:00:00+00:00"
itemprop="datePublished"
>
Aug 10, 2023
</time></p>

<a class="post" href="/tag/csharp">#csharp</a>

</header>

<div class="post-content e-content" itemprop="articleBody"><p>Lately, I’ve been writing a lot of services that use <a href="https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/top-level-statements">top-level statements</a>. The code with this kind of syntax sugar simplifies the <code class="language-plaintext highlighter-rouge">Main</code> method and improves readability. However, on the other hand, it makes it more difficult to create integration tests for the services. There isn’t simply way to call the <code class="language-plaintext highlighter-rouge">Main</code> method and pass the necessary arguments.</p>

<p>Since Microsoft introduced top-level statements in C# 9, you no longer need to write a weird Java-like <code class="language-plaintext highlighter-rouge">public static void Main(string[] args)</code> method. So the code</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">Application</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"args: </span><span class="p">{</span><span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">","</span><span class="p">,</span> <span class="n">args</span><span class="p">)}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>can be written just in one line:</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">System</span><span class="p">.</span><span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"args: </span><span class="p">{</span><span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">","</span><span class="p">,</span> <span class="n">args</span><span class="p">)}</span><span class="s">"</span><span class="p">);</span>
</code></pre></div></div>

<p>But what if we want to call this code and pass some arguments? By default, the C# compiler will convert the code above to the <a href="https://sharplab.io/#v2:D4AQTAjAsAULIQJwAoAkAiAhgJwOYGcAuAAgG8EAGAOgCkB7ASwDtl0Aad4nAgSgF90PANywgA==">following code</a>:</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">internal</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">static</span> <span class="k">void</span> <span class="p">&lt;</span><span class="n">Main</span><span class="p">&gt;</span><span class="err">$</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">Concat</span><span class="p">(</span><span class="s">"args: "</span><span class="p">,</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">","</span><span class="p">,</span> <span class="n">args</span><span class="p">)));</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The class is internal, and the method is private. You cannot call the <code class="language-plaintext highlighter-rouge">&lt;Main&gt;</code> method directly, especially from another assembly. How can you overcome this?</p>

<p>First of all, you should declare the <code class="language-plaintext highlighter-rouge">Program</code> class as <code class="language-plaintext highlighter-rouge">public partial</code>. This makes the <code class="language-plaintext highlighter-rouge">Program</code> class visible in external code. If you can’t change the code, you can load the type from the assembly using <a href="https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.gettype">Assembly.GetType</a>.</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">System</span><span class="p">.</span><span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"args: </span><span class="p">{</span><span class="kt">string</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">","</span><span class="p">,</span> <span class="n">args</span><span class="p">)}</span><span class="s">"</span><span class="p">);</span>

<span class="k">public</span> <span class="k">partial</span> <span class="k">class</span> <span class="nc">Program</span> <span class="p">{</span> <span class="p">}</span>
</code></pre></div></div>

<p>Now that the <code class="language-plaintext highlighter-rouge">Program</code> class has <a href="https://sharplab.io/#v2:D4AQTAjAsAULIQJwAoAkAiAhgJwOYGcAuAAgG8EAGAOgCkB7ASwDtl0Aad4nAgSgF90PANyx4AZmIAHHABcGmADbFwyiAHYyxPrCA===">become visible</a> from other assemblies, the <code class="language-plaintext highlighter-rouge">&lt;Main&gt;</code> method is still private. Using reflection, we can retrieve the <code class="language-plaintext highlighter-rouge">&lt;Main&gt;</code> method from the <code class="language-plaintext highlighter-rouge">DeclaredMethods</code> collection and call it using <code class="language-plaintext highlighter-rouge">Invoke</code>:</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">typeInfo</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Program</span><span class="p">)</span> <span class="k">as</span> <span class="n">TypeInfo</span> <span class="p">??</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">main</span> <span class="p">=</span> <span class="n">typeInfo</span><span class="p">.</span><span class="n">DeclaredMethods</span><span class="p">.</span><span class="nf">First</span><span class="p">(</span><span class="n">m</span> <span class="p">=&gt;</span> <span class="n">m</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">"&lt;Main&gt;"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">args</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="s">"arg1"</span><span class="p">,</span> <span class="s">"arg2"</span> <span class="p">};</span>
<span class="n">main</span><span class="p">.</span><span class="nf">Invoke</span><span class="p">(</span><span class="k">null</span><span class="p">,</span> <span class="k">new</span> <span class="kt">object</span><span class="p">[]</span> <span class="p">{</span> <span class="n">args</span> <span class="p">});</span>
</code></pre></div></div>

<p>That’s it. Reflection provides a powerful mechanism which helps us with writing tests for programs that use top-level statements.</p>
</div><a class="u-url" href="/2023/08/10/top-level-statements.html" hidden></a>
</article>

<script
src="https://utteranc.es/client.js"
repo="alexeyfv/blog"
issue-term="url"
label="comment"
theme="github-dark"
crossorigin="anonymous"
async
></script>

</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>

<div class="wrapper">

<div class="footer-col-wrapper">
<div class="footer-col">
<ul class="contact-list">
<li class="p-name">© 2024 Alexey Fedorov</li>
<li class="p-name">Powered by
<a href="https://github.com/jekyll/jekyll">Jekyll</a>
&
<a href="https://github.com/jekyll/minima">Minima</a>
</li>
</ul>
</div>
<div class="footer-col">
<p>Articles about .NET, C# and much more</p>
</div>
</div>

<div class="social-links"><ul class="social-media-list"><li><a rel="me" href="https://github.com/alexeyfv" target="_blank" title="alexeyfv"><svg class="svg-icon grey"><use xlink:href="/assets/minima-social-icons.svg#github"></use></svg></a></li><li><a rel="me" href="https://www.linkedin.com/in/alexeyfv" target="_blank" title="alexeyfv"><svg class="svg-icon grey"><use xlink:href="/assets/minima-social-icons.svg#linkedin"></use></svg></a></li><li><a rel="me" href="https://t.me/alexeyfv" target="_blank" title="alexeyfv"><svg class="svg-icon grey"><use xlink:href="/assets/minima-social-icons.svg#telegram"></use></svg></a></li></ul></div>

</div>

</footer></body>

</html>
Loading

0 comments on commit acf0d55

Please sign in to comment.