Bug 21273 - NSUserDefaults API does not take advantage of C# method overloading
Summary: NSUserDefaults API does not take advantage of C# method overloading
Status: CONFIRMED
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll (show other bugs)
Version: 7.9.1.x
Hardware: Macintosh Mac OS
: Normal enhancement
Target Milestone: Future Cycle (TBD)
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2014-07-11 17:50 UTC by Kevin Chen
Modified: 2014-09-08 10:38 UTC (History)
3 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description Kevin Chen 2014-07-11 17:50:27 UTC
In NSUserDefaults, the iOS API has separate methods for each type (stringForKey:, stringArrayForKey:, boolForKey:, etc) because Objective-C does not support overloaded methods. However, C# does, so all of these could be condensed down into a single method which is overloaded with all the correct types. 

As an illustration, here is the kludge I have in my code, which I think should be part of Mono:

        private class SettingsItem<T>
        {
            public string Key;
            private T cachedValue;

            private NSUserDefaults defaults = NSUserDefaults.StandardUserDefaults;

            public SettingsItem(string key)
            {
                this.Key = key;
            }

            public T Get()
            {
                if (cachedValue == null)
                {
                    // I really hope Mono's compiler optimizes this out when it fills out the template
                    if (typeof(T) == typeof(string)) cachedValue = defaults.StringForKey(Key);
                    //else if (typeof(T) == typeof(string[])) cachedValue = defaults.StringArrayForKey(Key);
                    else if (typeof(T) == typeof(int)) cachedValue = defaults.IntForKey(Key);
                    else if (typeof(T) == typeof(bool)) cachedValue = defaults.BoolForKey(Key);
                    else if (typeof(T) == typeof(double)) cachedValue = defaults.DoubleForKey(Key);
                    else if (typeof(T) == typeof(float)) cachedValue = defaults.FloatForKey(Key);
                    else if (typeof(T) == typeof(NSDictionary)) cachedValue = defaults.DictionaryForKey(Key);
                    else if (typeof(T) == typeof(NSData)) cachedValue = defaults.DataForKey(Key);
                    else if (typeof(T) == typeof(NSObject)) cachedValue = defaults[Key];
                }
                return cachedValue;
            }

            public void Set(T newValue)
            {
                cachedValue = newValue;

                if (typeof(T) == typeof(string)) defaults.SetString(newValue, Key);
                // everything else is similar to what's in Get()

                defaults.Synchronize(); // flush the changes to disk -- required
            }
        }
Comment 1 Rolf Bjarne Kvinge [MSFT] 2014-09-08 10:38:57 UTC
It's not possible to create a method overload that depends on the type of the return value, so what you suggest is not possible for the Get method.

For the Set* methods we could create an overloaded Set version, but your code wouldn't be simpler, since the compiler won't automatically convert T to whatever T is when the method is invoked, you'd end up with this code:

if (typeof (T) == typeof(string)) defaults.Set ((string) newValue, Key)
if (typeof (T) == typeof(double)) defaults.Set((double) newValue, Key)
etc.

What could be done are generic Set/Get methods (which would be pretty much a copy of your implementation).

Note You need to log in before you can comment on or make changes to this bug.