{"id":16473107,"url":"https://github.com/binki/ohnopub.implicitcastanalyzer","last_synced_at":"2026-06-10T08:31:21.393Z","repository":{"id":143134244,"uuid":"114516181","full_name":"binki/OhNoPub.ImplicitCastAnalyzer","owner":"binki","description":"Implicit cast analyzer for enumerable constructs in roslyn for C#.","archived":false,"fork":false,"pushed_at":"2018-01-22T03:55:11.000Z","size":40,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-28T12:40:46.340Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/binki.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-17T06:56:14.000Z","updated_at":"2021-03-29T12:20:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"ec12db24-8019-457e-a181-f3b833909e7d","html_url":"https://github.com/binki/OhNoPub.ImplicitCastAnalyzer","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/binki/OhNoPub.ImplicitCastAnalyzer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binki%2FOhNoPub.ImplicitCastAnalyzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binki%2FOhNoPub.ImplicitCastAnalyzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binki%2FOhNoPub.ImplicitCastAnalyzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binki%2FOhNoPub.ImplicitCastAnalyzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/binki","download_url":"https://codeload.github.com/binki/OhNoPub.ImplicitCastAnalyzer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binki%2FOhNoPub.ImplicitCastAnalyzer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34144679,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T12:25:21.659Z","updated_at":"2026-06-10T08:31:21.360Z","avatar_url":"https://github.com/binki.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿Analyzers for increasing type safety with looping constructs.\n\n# Rationale\n\nThe .net base class library contains two widely used interfaces to represent\nenumerables. Those are the untyped\n[`IEnumerable`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerable)\nand typed\n[`IEnumerable\u003cT\u003e`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1).\nVanilla C# and VB.NET has two constructs which support consuming both typed and untyped\nenumerables.\nFor C#, these are\n[`foreach`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in)\nand\n[LINQ query syntax](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/introduction-to-linq-queries).\nFor VB.NET, these are\n[`For Each…Next`](https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/for-each-next-statement)\nand\n[LINQ query syntax](https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/linq/introduction-to-linq#StructureOfALINQQuery).\n\nModern libraries and environments use typed enumerables. This\nmeans that the compiler can figure out an appropriate type when you use\ntype inference (the `var` keyword in C#, omitted `As` clause in VB.NET). For example:\n\n```csharp\nvar numbers = new[] { 1, 2, 3, };\nforeach (var i in numbers)\n{\n    int j = i;\n}\n```\n\n```vbnet\nFor Each i In { 1, 2, 3 }\n    Dim j As Integer = i\nNext\n```\n\nHowever, to support consuming untyped enumerables—the only option in .net-1.x—, these\nconstructs allow specification of a type to cast the element to. For\nexample, to loop over a winforms `ControlsCollection`, one may:\n\n```csharp\nforeach (Control control in Controls)\n{\n    Control myControl = control;\n}\n```\n\n```vbnet\nFor Each control As Control in Controls\n    Dim myControl As Control = control\nNext\n```\n\nThis works all fine and well when the programmer is absolutely certain about\nthe runtime types of values in the iterated collection and it is known that\nthe API will never change. For example, this is considered acceptable by many\nfor interacting with legacy untyped winforms APIs. But, this same feature has two issues.\nFirst, it results in a runtime cast with its performance penalty which, with\nsome planning/design/API improvement, may be unnecessary. Second and, in my opinion,\nmost importantly, this defers detection of some types of programming errors until\nruntime.\n\nFor example, the following will compile without error or warning even though any\nhuman glancing at the code could figure out that it is invalid:\n\n```csharp\nvar numbers = new object[] { 0.1, 0.2, 0.3, };\nforeach (int i in numbers)\n{\n\tConsole.WriteLine($\"i={i}, 2*i={2*i}\");\n}\n```\n\n```vbnet\n' Because VB.NET does runtime type coersion, this would run without exception\n' if the strings were, e.g., \"0.1\", \"4\". However, that is unexpected behavior\n' and effectively sidesteps the protections provided by Option Strict On.\nFor Each i As Integer in { \"uhm\", \"yeah!\" }\n    Console.WriteLine($\"i={i}, 2*i={2*i}\")\nNext\n```\n\nThis analyzer introduces a compile-time warning that detects when a runtime cast would\noccur. It also provides a codefix to conveniently convert the explicitly named type to\nuse inference to avoid the implicit runtime cast. This enables one to catch such issues at\ncompile time prior to even running tests. Additionally, it helps identify code\nwhich could be benefited by moving to generic collections.\n\nSee [dotnet/roslyn#14382](https://github.com/dotnet/roslyn/issues/14382).\n\n# TODO:\n\n* LINQ query support:\n  ```csharp\n  var q =\n      from int i from new object[]{ \"a\", \"b\", \"c\", }\n\t  select 2*i;\n  ```\n\n  ```vbnet\n  Dim q =\n      From i As Integer In { \"a\", \"b\", \"c\" }\n\t  Select 2*i\n  ```\n* VB.Net support. VB has basically the same constructs: . Right now,\n  this project only minimally supports C#. I do not know if the\n  actual analyzer can be generalized to support both C# and VB.Net\n  at the same time, but it has basically the same constructs and,\n  I assume, the same issues.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinki%2Fohnopub.implicitcastanalyzer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinki%2Fohnopub.implicitcastanalyzer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinki%2Fohnopub.implicitcastanalyzer/lists"}