Home > OS >  Restrict generic method for DTO models only (class & record)
Restrict generic method for DTO models only (class & record)

Time:04-06

Pretty straightforward question. I want to allow only DTO models in inputs (class & record types).

If I leave the class constraint only, I'm still able to put string in there. I want to not allow the primitive types.

If I put class, new(), it doesn't allow string just as expected, but I'm not allowed to use positional records either which is a problem.

public class Asd
{
    public string Name { get; set; }
}

public record Asd2(string Name);

public Task DoSomethingAsync<TInput>(TInput data) where TInput : class
{
    var message = JsonSerializer.Serialize(data); // if TInput is a string, it results into faulty \u0022 codes
}

Edit: The actual issue is that I have JsonSerializer.Serialize(data) inside that method and if a string is passed accidentally, it will result in something like:

"{\u0022Name\u0022:\u0022Test\u0022}"

CodePudding user response:

You need to have some kind of commonality for the restriction. This needs to be a common base class or interface.

As you want to use Records as well, then this must be an interface. But you can just define a simple, empty one if you want just for this purpose.

So you define a simple empty interface (better is if you actually have some common functions/properties).

public interface MyInterface
{

}

So then you code looks like this

public Task DoSomethingAsync<TInput>(TInput data) where TInput : MyInterface
{
}

And all your classes and records inherit from it like this.

public record AsdRecord: MyInterface
{
       //details here
}

public class AsdClass: MyInterface
{
        //details here
}

CodePudding user response:

If your list of allowed types can't be formulated with a type constraint, consider creating a list of allowed types (either hardcoded in code or with reflection at runtime e.g. on the namespace) and test against that list at runtime right at the beginning of the method (like you also test incoming parameters). Maybe something like this

private static readonly HashSet<Type> AllowedTypes = new HashSet<Type>
{
    typeof(MyTypeA),
    typeof(MyTypeB),
};

public Task DoSomethingAsync<TInput>(TInput data)
{
    if(!AllowedTypes.Contains(typeof(TInput)))
        throw new ArgumentException($"The type {typeof(TInput).Name} can' t be used here.");

    // ...
}

While this doesn't help you at compile time, at least it helps you at runtime.

  • Related