根据类型参数调用泛型方法中的不同方法
本文关键字:方法 泛型方法 类型参数 调用 | 更新日期: 2023-09-27 18:18:44
我有一些这样的方法:
public string GetStringValue(string field) { /* ... */ }
public int GetIntValue(string field) { /* ... */ }
现在我想写一个泛型方法,它有以下签名:
public bool CopyValue<T>(string field, Action<T> copyAction)
根据类型参数,我想用一个非泛型方法的返回值来调用copyAction
。我的第一个尝试是
public bool CopyValue<T>(string field, Action<T> copyAction)
{
if (typeof(T) == typeof(string))
copyAction((GetStringValue(field));
else if (typeof(T) == typof(int))
copyAction(GetIntValue(field));
else
return false;
return true;
}
但是这甚至不能编译。然后我尝试将非泛型方法包装在泛型方法中,如
public string GetValue<string>(string field)
{
return GetStringValue(field);
}
显然也不能编译。
这可以做到还是我必须显式实现CopyValue
为每个类型?
您可以使用强制转换,但它很难看:
if (typeof(T) == typeof(string))
{
copyAction((T)(object) GetStringValue(field));
}
(等)
老实说,这种事情最终总是相当丑陋的。一种选择是创建一个像这样的Dictionary<Type, Delegate>
:
Dictionary<Type, Delegate> fieldExtractors = new Dictionary<Type, Delegate>
{
{ typeof(string), (Func<string, string>) field => GetStringValue(field) },
{ typeof(int), (Func<string, int>) field => GetIntValue(field) },
};
那么你可以使用:
public bool CopyValue<T>(string field, Action<T> copyAction)
{
Delegate fieldExtractor;
if (fieldExtractors.TryGetValue(typeof(T), out fieldExtractor))
{
var extractor = (Func<string, T>) fieldExtractor;
copyAction(extractor(field));
return true;
}
return false;
}
如果您可以重构一些代码,您可以使用这个技巧。最大的优点是,这是在编译时完成的,而不是在运行时:
public class JsonDictionary
{
public static readonly Key<int> Foo = new Key<int> { Name = "FOO" };
public static readonly Key<string> Bar = new Key<string> { Name = "BAR" };
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(Key<T> key, T obj)
{
_data[key.Name] = obj;
}
public T Get<T>(Key<T> key)
{
return (T)_data[key.Name];
}
public class Key<T>
{
public string Name { get; init; }
}
}
在我的例子中,我可以替换a:
Dictionary<Type, Delegate> jsonElementDelegates = new Dictionary<Type, Delegate>
{
{ typeof(string), (Func<JsonElement, string>) (arrayItem => arrayItem.GetString()!) },
{ typeof(float), (Func<JsonElement, float>)(arrayItem => arrayItem.GetSingle()) },
{ typeof(double), (Func<JsonElement, double>) (arrayItem => arrayItem.GetDouble()) },
{ typeof(short), (Func<JsonElement, short>)(arrayItem => arrayItem.GetInt16()) },
{ typeof(ushort), (Func<JsonElement, ushort>) (arrayItem => arrayItem.GetUInt16()) },
{ typeof(int), (Func<JsonElement, int>)(arrayItem => arrayItem.GetInt32()) },
{ typeof(uint), (Func<JsonElement, uint>) (arrayItem => arrayItem.GetUInt32()) },
{ typeof(long), (Func<JsonElement, long>)(arrayItem => arrayItem.GetInt64()) },
{ typeof(ulong), (Func<JsonElement, ulong>) (arrayItem => arrayItem.GetUInt64()) },
};
与编译时等效的
public static readonly Converter<string> ConvString = new Converter<string> { Fun = arrayItem => arrayItem.GetString()! };
public static readonly Converter<float> ConvFloat = new Converter<float> { Fun = arrayItem => arrayItem.GetSingle() };
public static readonly Converter<double> ConvDouble = new Converter<double> { Fun = arrayItem => arrayItem.GetDouble() };
public static readonly Converter<short> ConvShort = new Converter<short> { Fun = arrayItem => arrayItem.GetInt16() };
public static readonly Converter<ushort> ConvUShort = new Converter<ushort> { Fun = arrayItem => arrayItem.GetUInt16() };
public static readonly Converter<int> ConvInt = new Converter<int> { Fun = arrayItem => arrayItem.GetInt32() };
public static readonly Converter<uint> ConvUInt = new Converter<uint> { Fun = arrayItem => arrayItem.GetUInt32() };
public static readonly Converter<long> ConvLong = new Converter<long> { Fun = arrayItem => arrayItem.GetInt64() };
public static readonly Converter<ulong> ConvULong= new Converter<ulong> { Fun = arrayItem => arrayItem.GetUInt64() };
public class Converter<T>
{
public Func<JsonElement, T> Fun { get; init; }
}
参考:- c#:在异构字典 上暴露类型安全API
- https://stackoverflow.com/a/2178769/136285