How to specify general parameters of a method type partially

I have an extension method as shown below:

public static T GetValueAs<T, R>(this IDictionary<string, R> dictionary, string fieldName) where T : R { R value; if (!dictionary.TryGetValue(fieldName, out value)) return default(T); return (T)value; } 

Currently, I can use it as follows:

  var dictionary = new Dictionary<string, object>(); //... var list = dictionary.GetValueAs<List<int>, object>("A"); // this may throw ClassCastException - this is expected behavior; 

It works very well, but the second type parameter is really annoying. Is it possible to rewrite GetValueAs in C # 4.0 so that the method will still be applied to various types of dictionaries with string keys. And there is no need to specify a parameter of the second type in the calling code, i.e. Use

  var list = dictionary.GetValueAs<List<int>>("A"); 
or at least something like
  var list = dictionary.GetValueAs<List<int>, ?>("A"); 
instead
  var list = dictionary.GetValueAs<List<int>, object>("A"); 
+4
source share
4 answers

As long as you use it only in object dictionaries, you can restrict T to a reference type to make it valid:

 public static T GetValueAs<T>(this IDictionary<string, object> dictionary, string fieldName) where T : class { object value; if (!dictionary.TryGetValue(fieldName, out value)) return default(T); return (T)value; } 

But that is probably not what you want. Please note that C # version 4 also does not solve your problem .

+1
source

What about

 public static void GetValueAs<T, R>(this IDictionary<string, R> dictionary, string fieldName, out T value) where T : R { value = default(T); dictionary.TryGetValue(fieldName, out value) } 

Then you can do something like

 List<int> list; dictionary.GetValueAs("fieldName", out list); 

Basically, to determine that T you should have something like T in the parameters.

Edit

Perhaps the best way is

 public static T GetValueAs<T, R>( this IDictionary<string, R> dictionary, string fieldName, T defaultValue) where T : R { R value = default(R); return dictionary.TryGetValue(fieldName, out value) ? (T)value : defaultValue; } 

Then you can use var and chain, and this gives you the ability to control what the default is.

 var x = dict.GetValueAs("A", new Dictionary<string,int>).GetValueAs("B", default(int)); 
0
source

Maybe you can create your own vocabulary class for this behavior:

  public class CastableDictionary<TKey, TValue> : Dictionary<TKey, TValue> { public TOut GetValueAs<TOut>(TKey key) where TOut : TValue { TValue result; if (this.TryGetValue(key, out result)) { return (TOut)result; } return default(TOut); } } var d = new CastableDictionary<string, object>(); d.Add("A", 1); d.Add("B", new List<int>() { 1, 2, 3}); var a = d.GetValueAs<int>("A"); // = 1 var b = d.GetValueAs<List<int>>("B"); //= 1, 2, 3 

I probably do not want to do this, be it hay.

0
source

Am I missing something, of course, is that all you want? You may need to improve the conversion, but for the general actor, this should do:

 public static T getValueAs<T>(this IDictionary dict, string key) { try { return (T)dict[key]; } catch { return default(T); } } 

use is simple

 MyDictionary.getValueAs<Int32>("hello"); 

With IDictionary, you don’t need to specify types for the key and value, however, since the dictionary inherits, the function remains, no matter how your dictionary is created. You can even just use an object instead of a string for a key.

0
source

Source: https://habr.com/ru/post/1306120/


All Articles