Generic class where type 可以解析字符串
Generic class where type can Parse strings
我想创建一个泛型 class,其中 class 的类型可以解析字符串。
我想将此 class 用于任何具有静态函数 Parse(string) 的 class,
像 System.Int32、System.Double,但也像 System.Guid 这样的 class。他们都有一个静态的解析函数
所以我的 class 需要一个 where 子句来将我的泛型类型限制为具有 Parse 函数的类型
我想这样使用它:
class MyGenericClass<T> : where T : ??? what to do ???
{
private List<T> addedItems = new List<T>()
public void Add(T item)
{
this.AddedItems.Add(item);
}
public void Add(string itemAsTxt)
{
T item = T.Parse(itemAsTxt);
this.Add(item);
}
}
where子句写什么?
你根本不能在编译时这样做。除了名称之外,所有这些方法没有 任何 共同点。它们既没有在任何公共接口中定义,也没有相同的参数。
想象一下,您有自己的方法,但意外地使用了该名称,但做的事情却完全不同。此外,它也是一个实例方法:
class MyType
{
void Parse() { ... }
}
如您所见,该方法甚至没有 any 参数,因此很难在 - 例如 - int.Parse(myString)[ 之间找到任何共同逻辑=12=]myInstanceOfMyType.Parse()`。
但即使 if 你也可以做到。你会用 item
做什么?没有太多,因为他们之间没有任何共同点。特别是不可能调用 methpd,因为它们完全不同。
但是您可以在运行时使用类似的方法循环所有类型:
var types = allAssemblies.SelectMany(x => x.GetTypes())
.Where(x => x.GetMethod("Parse") != null);
但请注意,如果每个类型的名称中存在多个方法,这会产生 AmbiguousMatchException
,这就是方法重载的时候。
我可能误解了你的问题,但这能解决问题吗?
static void Main(string[] args)
{
Guid g = DoParse<Guid>("33531071-c52b-48f5-b0e4-ea3c554b8d23");
}
public static T DoParse<T>(string value)
{
T result = default(T);
MethodInfo methodInfo = typeof(T).GetMethod("Parse");
if (methodInfo != null)
{
ParameterInfo[] parameters = methodInfo.GetParameters();
object classInstance = Activator.CreateInstance(typeof(T), null);
object[] parametersArray = new object[] { value };
result = (T)methodInfo.Invoke(methodInfo, parametersArray);
}
return result;
}
我对使用反射进行解析的答案不满意。
我更喜欢类型安全的解决方案,这样编译器会抱怨缺少 Parse 函数。
通常您会限制为具有接口的 class。但正如其他人所说,没有通用接口。想想看,我不需要接口,我需要一个可以调用的函数
所以我的解决方案是坚持要求创建者向解析函数提供一个委托,该委托将解析字符串以键入 T
class MyGenericClass<T>
{
public MyGenericClass(Func<string, T> parseFunc)
{
this.parseFunc = parseFunc;
}
private readonly Func<string, T> parseFunc;
public void Add(string txt)
{
this.Add(parseFunc(txt));
}
}
用法:
MyGenericClass<Guid> x = new MyGenericClass<Guid>(txt => Guid.Parse(txt));
MyGenericClass<int> y = new MyGenericClass<int> (txt => System.Int32.Parse(txt));
答案比我想象的要简单
我想创建一个泛型 class,其中 class 的类型可以解析字符串。
我想将此 class 用于任何具有静态函数 Parse(string) 的 class, 像 System.Int32、System.Double,但也像 System.Guid 这样的 class。他们都有一个静态的解析函数
所以我的 class 需要一个 where 子句来将我的泛型类型限制为具有 Parse 函数的类型
我想这样使用它:
class MyGenericClass<T> : where T : ??? what to do ???
{
private List<T> addedItems = new List<T>()
public void Add(T item)
{
this.AddedItems.Add(item);
}
public void Add(string itemAsTxt)
{
T item = T.Parse(itemAsTxt);
this.Add(item);
}
}
where子句写什么?
你根本不能在编译时这样做。除了名称之外,所有这些方法没有 任何 共同点。它们既没有在任何公共接口中定义,也没有相同的参数。
想象一下,您有自己的方法,但意外地使用了该名称,但做的事情却完全不同。此外,它也是一个实例方法:
class MyType
{
void Parse() { ... }
}
如您所见,该方法甚至没有 any 参数,因此很难在 - 例如 - int.Parse(myString)[ 之间找到任何共同逻辑=12=]myInstanceOfMyType.Parse()`。
但即使 if 你也可以做到。你会用 item
做什么?没有太多,因为他们之间没有任何共同点。特别是不可能调用 methpd,因为它们完全不同。
但是您可以在运行时使用类似的方法循环所有类型:
var types = allAssemblies.SelectMany(x => x.GetTypes())
.Where(x => x.GetMethod("Parse") != null);
但请注意,如果每个类型的名称中存在多个方法,这会产生 AmbiguousMatchException
,这就是方法重载的时候。
我可能误解了你的问题,但这能解决问题吗?
static void Main(string[] args)
{
Guid g = DoParse<Guid>("33531071-c52b-48f5-b0e4-ea3c554b8d23");
}
public static T DoParse<T>(string value)
{
T result = default(T);
MethodInfo methodInfo = typeof(T).GetMethod("Parse");
if (methodInfo != null)
{
ParameterInfo[] parameters = methodInfo.GetParameters();
object classInstance = Activator.CreateInstance(typeof(T), null);
object[] parametersArray = new object[] { value };
result = (T)methodInfo.Invoke(methodInfo, parametersArray);
}
return result;
}
我对使用反射进行解析的答案不满意。
我更喜欢类型安全的解决方案,这样编译器会抱怨缺少 Parse 函数。
通常您会限制为具有接口的 class。但正如其他人所说,没有通用接口。想想看,我不需要接口,我需要一个可以调用的函数
所以我的解决方案是坚持要求创建者向解析函数提供一个委托,该委托将解析字符串以键入 T
class MyGenericClass<T>
{
public MyGenericClass(Func<string, T> parseFunc)
{
this.parseFunc = parseFunc;
}
private readonly Func<string, T> parseFunc;
public void Add(string txt)
{
this.Add(parseFunc(txt));
}
}
用法:
MyGenericClass<Guid> x = new MyGenericClass<Guid>(txt => Guid.Parse(txt));
MyGenericClass<int> y = new MyGenericClass<int> (txt => System.Int32.Parse(txt));
答案比我想象的要简单