Skip to content

BMTLab/ImeiType

Repository files navigation

BMTLab.ImeiType

Release Build CodeQL NuGet Nuget Downloads

BMTLab.ImeiType is a .NET library that provides a strongly-typed IMEI (International Mobile Equipment Identity) readonly struct. It offers a simple API for validation, parsing, and generating IMEI numbers. This package helps improve type safety, reduce errors, and handle IMEI values consistently in your applications.

Supported Platforms
- .NET 9.0, 8.0, 7.0, 6.0, and
- .NET Standard 2.1

Installation

Install via NuGet:

dotnet add package BMTLab.ImeiType

Or edit your .csproj:

<PackageReference Include="BMTLab.ImeiType" Version="1.1.0" />

Features

public readonly struct Imei
  : IEquatable<Imei>, 
    IEqualityOperators<Imei, Imei, bool>, // .NET 7.0 or greater
    ISpanParsable<Imei>,                  // .NET 7.0 or greater
    IUtf8SpanParsable<Imei>               // .NET 8.0 or greater
  1. Strongly-Typed Imei Struct

Stores the IMEI number (long) internally. Providing high-performance methods and approaches with minimized memory allocation, as well as a set of specific tweaks and interface implementations for each supported platform.

  1. Multiple Parsing And Creation Options

Imei.Parse(...) and Imei.TryParse(...) from long, string, ReadOnlySpan<char>, or ReadOnlySpan<byte> (UTF-8) with overload options.

  1. Random IMEI Generation
Imei.NewRandomImei();         // Creates a secure random IMEI using secure RandomNumberGenerator.
Imei.NewRandomImei(int seed); // Useful for testing or reproducible results.
  1. Detailed IMEI Parts & Constants
Imei.Tac; // Type Allocation Code ('35', e.g.)
Imei.Fac; // Final Assembly Code  ('630348', e.g.)
Imei.Snr; // Serial Number        ('991680', e.g.)
public const int Length = 15;

// Minimum and maximum allowed value of IMEI number
public const long MinValue = 00_000000_000001_9; 
public const long MaxValue = 99_999999_999999_4;
  1. Conversions

    βœ… Implicit conversion to string, ReadOnlySpan<char>, and ReadOnlySpan<byte>;

    βœ… Explicit conversion from long, string, or spans;

    βœ… Helper methods: ToInt64(), ToReadOnlySpan() and ToUtf8() and vice versa ToImei().

  2. Validation

Checks values of different types to see if the value is a valid IMEI (via Luhn checksum).

Quick Example

Initialization

using BMTLab.ImeiType;

// This line shall not compile
Imei illegal = new Imei();
    
// Create an IMEI from a long (int64)
Imei imei1 = new Imei(356303489916807);

// From string or char arrays (or spans)
Imei imei2 = new Imei("356303489916807");
Imei imei3 = new Imei("356303489916807".AsSpan());
Imei imei4 = new Imei(['3', '5', '6', '3', '0', '3', '4', '8', '9', '9', '1', '6', '8', '0', '7']);

// From UTF-8 text
Imei imei5 = new Imei("356303489916807"u8);
Imei imei6 = new Imei([0x33, 0x35, 0x36, 0x33, 0x30, 0x33, 0x34, 0x38, 0x39, 0x39, 0x31, 0x36, 0x38, 0x30, 0x37]);

Important

Because Imei is a readonly struct, a parameterless constructor cannot be fully removed. We therefore mark the empty constructor with [Obsolete(error: true)] to prevent its usage.

Alternatively, you can cast values into an Imei:

using BMTLab.ImeiType;

Imei imei1 = (Imei) 356303489916807;
Imei imei2 = (Imei) "356303489916807";
Imei imei3 = (Imei) "356303489916807".AsSpan();
Imei imei4 = (Imei) new char[] {'3', '5', '6', '3', '0', '3', '4', '8', '9', '9', '1', '6', '8', '0', '7'};
Imei imei5 = (Imei) "356303489916807"u8;
Imei imei6 = (Imei) stackalloc byte[] { 0x33, 0x35, 0x36, 0x33, 0x30, 0x33, 0x34, 0x38, 0x39, 0x39, 0x31, 0x36, 0x38, 0x30, 0x37 };

Or parse it, for example:

using BMTLab.ImeiType;

bool canBeParsedAndValid = Imei.TryParse(356303489916807, out Imei parsedImei);
// ...and so on

Validation

By default, every new Imei(...) is validated to ensure the 15-digit number is correct, according to the IMEI specification (using a Luhn checksum).

To avoid getting a FormatException during creation, you can use one of these overloads to check validity (return boolean):

  • IsValid(long)
  • IsValid(ReadOnlySpan<byte>)
  • IsValid(ReadOnlySpan<char>)
  • IsValid(string?)
  • IsValid(Imei) - in case Imei was created via default(Imei), which unfortunately we cannot restrict.

Tip

If you are sure that the passed value will never be wrong, you can disable the check on creation and improve performance a bit. To do this, set this static property:

/* (`true` by default) can be set to `false` to skip validation on creation (use carefully) */
Imei.ShouldValidateWhileInitialization = false; 

Important

but use this at your own risk as it will affect the behavior globally.

Conversion

Where a primitive type is expected, the IMEI type itself can easily be used, typically:

using BMTLab.ImeiType;

var imei = (Imei) 356303489916807;

string imeiAsString = imei;
ReadOnlySpan<char> imeiAsCharSpan = imei;
ReadOnlySpan<byte> imeiAsUtf8Text = imei;

/* Conversion to long is explicit, it is necessary to avoid ambiguous type reference when printing e.g. */
long imeiAsLong = (long) imei; 
Console.WriteLine($"IMEI value: {imei}"); //> "IMEI value: 015434904561440", e.g.

Equality check

using BMTLab.ImeiType;

var imeiA = (Imei) "356303489916807";
var imeiB = (Imei) "356303489916807";

Console.WriteLine(imeiA == imeiB);      //> true
Console.WriteLine(imeiA.Equals(imeiB)); //> true

Generating a new random IMEI

using BMTLab.ImeiType;

var newImeiA = Imei.NewRandomImei(seed: 42); // By using System.Random. Useful for testing or reproducible results
var newImeiB = Imei.NewRandomImei();         // By using System.Security.Cryptography

WriteLine($"Random IMEI (with seed): {newImeiA}");
WriteLine($"Random IMEI (secure, but slower a bit): {newImeiB}");

BMTLab.ImeiType.SystemTextJson

BMTLab.ImeiType.SystemTextJson is an optional add-on package that provides JSON serialization and deserialization of Imei values using the built-in System.Text.Json APIs.

It includes a specialized converter: JsonImeiConverter, which can read IMEI numbers from JSON as either numeric or string values, and write them back in a controlled manner.

The converter also supports IMEIs as list items, keys or dictionary values.

Supported Platforms
.NET 9.0, 8.0, 7.0, 6.0

Installation

dotnet add package BMTLab.ImeiType.SystemTextJson

Or edit your .csproj:

<PackageReference Include="BMTLab.ImeiType.SystemTextJson" Version="1.1.0" />

Usage

using System.Text.Json;
using BMTLab.ImeiType.SystemTextJson.Extensions;

var options = new JsonSerializerOptions().WithImeiConverter();               // Configure with IMEI converter

var obj = new ImeiContainer { Val = (Imei) 356303489916807 };
var json = JsonSerializer.Serialize(obj, options);                           //> { "val": 356303489916807 }
var deserialized = JsonSerializer.Deserialize<ImeiContainer>(json, options); //> ImeiContainer with Imei property set

Extension Methods

For convenience, you can use one of the suggested extension methods:

  • .WithImeiConverter(JsonImeiWriteOptions writeOptions = JsonImeiWriteOptions.Default) (on JsonSerializerOptions) Attaches the IMEI converter with a chosen writing strategy.
  • .AddImeiConverter(JsonImeiWriteOptions writeOptions = JsonImeiWriteOptions.Default) (on IList<JsonConverter>) Allows adding the same converter in a more granular manner if you manage your own converter list.

JsonImeiWriteOptions

The enum JsonImeiWriteOptions specifies how to write the IMEI (number, string, or auto-select based on JsonSerializerOptions.NumberHandling).

[DefaultValue(Default)]
public enum JsonImeiWriteOptions
{
    /// <summary>
    ///     Applies the default logic based on <see cref="JsonSerializerOptions.NumberHandling" />
    ///     to determine how IMEIs is written.
    /// </summary>
    Default = 0,

    /// <summary>
    ///     Always writes IMEIs as a numeric (for example, <c>{"val": 356303489916807}</c>).
    /// </summary>
    ForceWriteAsNumber,

    /// <summary>
    ///     Always writes IMEIs as a string (for example, <c>{"val": "356303489916807"}</c>).
    /// </summary>
    ForceWriteAsString
}

Future Ideas

I plan to add a couple of new optional extension projects for ImeiType, such as integration with EF Core / Dapper.


Notice

This project uses the dependency FluentAssertions version 7.0.0, which is distributed under a license other than MIT β€” Apache 2.0 β€” but the ImeiType project does not include any binary files or source code of FluentAssertions.

Please feel free to fork this, contribute or let me know if you find a bug. Any ideas for improvement are always welcome as well πŸ˜‡

About

.NET library that provides a strongly-typed IMEI readonly struct type and corresponding utility methods

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Contributors 2

  •  
  •