Infer Method-Return Type which is generic type of another type

Viewed 93

I've got a generic base class with one implementation:

public abstract class Setting<T> : ISetting
{
    public T DefaultValue { get; }
}

public class SubscribeToNewsletterSetting : Setting<bool>
{
   ...
}

Now I've got a settings class, using this settings:

public class UserSettings
{
    public TSetting GetSetting<TSetting>(int ownerId)
        where TSetting : ISetting
    {
        ....
    }
}

Now I can use the UserSettings class like this:

var setting = settings.GetSetting<SubscribeToNewsletterSetting>(22);
var settingsValue = setting.DefaultValue;

Now I was wondering - Is it possible to do this in one step, without specifing the type: e.g:

var settingsValue = settings.GetSettingDefaultValue<SubscribeToNewsletterSetting>(22);

(I do not want to call it like this)

var settingsValue = settings.GetSettingDefaultValue<SubscribeToNewsletterSetting, bool>(22);

Cheers, Manuel

2 Answers

Unfortunately that is not possible. Type inference of generic parameters is an all or nothing proposition. Either all parameters can be inferred and you have to (explicitly) specify none, or you have to specify them all explicitly.

You only have the choice between the following to variants:

public class UserSettings
{

    // Variant A
    public TSetting GetSetting<TSetting>(int ownerId)
        where TSetting : ISetting
    {
        return default;
    }

    // Variant B
    public TValue GetSettingValue<TSetting, TValue>(int ownerId)
        where TSetting : Setting<TValue>
    {
        return default;
    }
}

Which you can use like this. Where x,y,z should all be implicitly typed as bool.

class Demo
{
    public void Run()
    {
        var us = new UserSettings();

        // Variant A
        var x = us.GetSetting<SubscribeToNewsletterSetting>(22).DefaultValue;

        // Variant B 
        var y = us.GetSettingValue<SubscribeToNewsletterSetting, bool>(22);

        // desired, but impossible
        var z = us.GetSettingValue<SubscribeToNewsletterSetting>(22);
    }
}

My recommendation would be to add a public T Value {get;} property to Settings<T> and add the database access code (or at least the strong typing part of it) to 'SubscribeToNewsletterSetting' (where the TValue type is known).

if I'm correctly understood question you want to consider instance of SubscribeToNewsletterSetting also as a boolean value, if so... then you can do next:

    public abstract class Setting<T>
    {
        public T DefaultValue { get; }

        public static implicit operator T(Setting<T> value)
        {
            return value.DefaultValue;
        }
    }

    public class SubscribeToNewsletterSetting : Setting<bool>
    {
    }


    public static async Task Main()
    {
        ...
        // Will work fine.
        bool isEnabled = settings.GetSetting<SubscribeToNewsletterSetting>(22);
    }
Related