1

I need to use two versions of base type in the same generic: nullable and non-nullable. Like int? and int, Guid? and Guid, DateOnly? and DateOnly and so on. Nullable type should be at the class property, non-nullable should be at class dictionary's key. And nullable should be used to search on that dictionary.

Example:

var t = new GenericTest<int?, int> # ERROR: The type 'int?' must be convertible to 'int' in order to use it as parameter 'TK' in the generic class 'GenericTest<TK,TV>'
{
    Key = null
};
t.Values.Add(1, 2);

Console.WriteLine(t.FindValue());

class GenericTest<TK, TV> 
    where TK: TV
    where TV : notnull
{
    public TK? Key { get; set; }
    
    public Dictionary<TV, int> Values { get; set; } = new();

    public int FindValue()
    {
        if (Key == null)
            return 0;
        
        return Values.GetValueOrDefault(Key, 0);
    }
}

I also tried to use only 1 generic parameter, but got warning

var t = new GenericTest<int?>
{
    Key = null
};
t.Values.Add(1, 3);

Console.WriteLine(t.FindValue());

class GenericTest<TK>
{
    public TK? Key { get; set; }
    
    public Dictionary<TK, int> Values { get; set; } = new(); # WARNING: Nullability of type argument 'TK' must match 'notnull' constraint in order to use it as parameter 'TKey'

    public int FindValue()
    {
        if (Key == null)
            return 0;
        
        return Values.GetValueOrDefault(Key, 0);
    }
}

Ok, I'm adding constraint, but getting another warning:

var t = new GenericTest<int?> # WARNING: Nullability of type argument 'int?' must match 'notnull' constraint in order to use it as parameter 'TK'
{
    Key = null
};
t.Values.Add(1, 3);

Console.WriteLine(t.FindValue());

class GenericTest<TK> where TK : notnull # ADDED HERE
{
    public TK? Key { get; set; }
    
    public Dictionary<TK, int> Values { get; set; } = new();

    public int FindValue()
    {
        if (Key == null)
            return 0;
        
        return Values.GetValueOrDefault(Key, 0);
    }
}

Is it possible to achieve that without errors and warnings?

2
  • What are the warnings you receive when you try the two solutions? Commented Dec 17, 2024 at 17:03
  • 1
    @maccettura I specified right in the comments in the code blocks Commented Dec 18, 2024 at 19:03

1 Answer 1

2

I'm not totally sure if this is what you're after, but: If you want to always use the type T? for the key and T for the value, you can avoid having to specify two type parameters like so:

class GenericTest<TK> where TK : struct
{
    public TK? Key { get; init; }

    public Dictionary<TK, TK> Values { get; set; } = new();

    public TK FindValue()
    {
        if (Key == null)
            return default;

        return Values.GetValueOrDefault(Key.Value, default);
    }
}

This will work for any struct type, which of course includes int, Guid and DateOnly.

Your sample would then look more like this:

static void Main()
{
    var t = new GenericTest<int>
    {
        Key = 1
    };
    t.Values.Add(1, 2);

    Console.WriteLine(t.FindValue());
}
Sign up to request clarification or add additional context in comments.

2 Comments

Your example still gives the warning Nullability of type argument 'TK?' must match 'notnull' constraint in order to use it as parameter 'TKey'. If the project option "Treat Warnings as Errors" is enabled - as we need in our project - warning turns into error. For sure I can ignore the warning by #pragma warning disable CS8714 but I'm not sure this is the good solution
@DoctorCoder Sorry, I confused the key and the value - should be fixed now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.