Xamarin.Essentials.Preferences set/get with generic type in Xamarin.Forms

379 Views Asked by At
public class PreferenceManager
{
    private static PreferenceManager _instance = null;
    private static readonly object _lock = new object();

    private PreferenceManager() { }
    public static PreferenceManager Instance
    {
        get
        {
            lock (_lock)
            {
                if (_instance == null)
                    _instance = new PreferenceManager();

                return _instance;
            }
        }
    }

    public void SetPreference<T>(string key, T value)
    {
        Preferences.Set(key, value);
    }
    public T GetPreference<T>(string key)
    {
        object value = Preferences.Get(key, null);
        return (T)Convert.ChangeType(value, typeof(T));
    }
}

I'd like to make wrapper class for manage all process about Xamarin.Essentials.Preferences.

There are so many overrides with different types for getting/setting in Essentials class.

So, I tried to change return value with generic and set value also, because I think it looks more simple.

But, there is an error in SetPreference method : cannot convert from 'T' to 'string'.

Is there any good solution for making wrapper class?

I want to handle all processes in here with one method.... :-(

2

There are 2 best solutions below

1
Liqun Shen-MSFT On BEST ANSWER

According to Xamarin Essentials Preferences.shared.cs on Github, set method in Preferences doesn't support generic type. So we could not wrap it in a generic setter directly.

And only seven data types are supported in Xamarin Preferences accoridng to Xamarin.Essentials: Preferences. I could only code for each data types like the following code:

public void SetPreference<T>(string key,T value)
{
    if (value is string)
    {
        Preferences.Set(key, Convert.ToString(value));              
    }
    if (value is double)
    {
        Preferences.Set(key, Convert.ToDouble(value));
    }
    ...
}

Hope it works for you.

0
SKall On

If you want to store classes only, you could simply use a serializer:

    public class PreferenceManager
    {
        private static readonly Lazy<PreferenceManager> LazyInstance = new Lazy<PreferenceManager>(() => new PreferenceManager());

        private PreferenceManager() { }
        public static PreferenceManager Instance => LazyInstance.Value;

        public void SetPreference<T>(string key, T value) where T : class => Preferences.Set(key, JsonSerializer.Serialize(value));

        public T GetPreference<T>(string key) where T : class => Preferences.Get(key, null) is string value
            ? JsonSerializer.Deserialize<T>(value)
            : default;
    }

If you want to store also non-classes, then easiest way would to wrap the object into a class:

public class PreferenceManager
{
    private static readonly Lazy<PreferenceManager> LazyInstance = new(() => new PreferenceManager());

    private PreferenceManager() { }
    public static PreferenceManager Instance => LazyInstance.Value;

    public void SetPreference<T>(string key, T value) => Preferences.Set(key, JsonSerializer.Serialize(new StoredObject<T>(value)));

    public T GetPreference<T>(string key)
    {
        var o = Preferences.Get(key, null) is { } value
            ? JsonSerializer.Deserialize<StoredObject<T>>(value)
            : null;

        return o is not null ? o.Value : default;
    }

    public class StoredObject<T>
    {
        public StoredObject() {}
    
        public StoredObject(T value)
        {
            Value = value;
        }

        public T Value { get; set; }
    }
}