如何从Template调用方法
本文关键字:调用 方法 Template | 更新日期: 2023-09-27 17:57:52
我有一个C#WinForms代码,其中有几个不同的structs
,它们都以相同的方式工作。因此,我不再编写用于添加或删除项目的单独函数,而是尝试使用Templates。
例如,这里有一个struct
和相应的List<>
,我用来存储它的objects
:
public struct Alias
{
public string alias;
public string aliasSource;
public static bool IsValid(...); //This function exists in all the structs
};
List<Alias> aliases;
这是从外部使用的函数,用于添加别名:
public void AddAlias(Alias iAlias)
{
AddGenericStructItem<Alias>(iAlias, aliases);
}
这是做加法的实际函数:
private void AddGenericStructItem<T>(T genericStructItem, List<T> genericList)
{
string outputError;
if (T.IsValid(genericStructItem, out outputError)) //< -- Problem in the 'T' being used in the far left
{
if (genericList.Contains(genericStructItem))
{
MessageBox.Show("ERROR 82ha5jb :: Item already exists");
}
else
{
genericList.Add(genericStructItem);
}
}
else
{
MessageBox.Show(outputError);
}
}
问题出现在T.IsValid...
部分。编译器在T
上给我以下错误:
'T' is a 'type parameter', which is not valid in the given context
有办法解决这个问题吗?我所有的structs
都有一个IsValid
函数,具有相同的设置,所以重复编写相同的代码似乎很愚蠢,以防我在这里不使用模板。。。
你不能那样做。唯一的选择是将泛型参数的where
约束定义为某种接口或基类类型。但是,无论是使用结构还是静态成员,都无法做到这一点。如果您将结构更改为类,那么您可以执行以下操作:
public interface IValidatable
{
bool IsValid(out outputError);
}
public class Alias : IValidatable
{
public string alias;
public string aliasSource;
public bool IsValid(out outputError) { ... };
};
现在您可以应用约束:
private void AddValidatableItem<T>(T item, List<T> list)
where T : IValidatable
{
string outputError;
if (!item.IsValid(out outputError))
{
MessageBox.Show(outputError);
return;
}
if (list.Contains(item))
{
MessageBox.Show("ERROR 82ha5jb :: Item already exists");
return;
}
list.Add(item);
}
顺便说一句,你可以利用C#扩展方法,使这个方法成为可验证项目列表的扩展:
public static void AddValidatableItem<T>(this List<T> list, T item)
where T : IValidatable
这将允许您调用列表中的方法:
aliases.AddValidatableItem(newAlias);
不能使用约束来告诉编译器对象上将存在静态方法。如果它真的需要是静态的,那么您需要使用反射来调用方法:
var methodInfo = typeof(T).GetMethod("IsValid", BindingFlags.Static|BindingFlags.Public);
if (methodInfo != null)
{
object[] parameters = new object[] { genericStructItem, null };
if ((bool)methodInfo.Invoke(null, parameters))
{
// It's valid!
}
else
{
string error = (string)parameters[1];
}
}
C#泛型与C++中的模板有显著的不同,尽管语法看起来相似。
当你说
T.IsValid(genericStructItem, out outputError);
听起来您希望编译器用Alias
替换T
,以提供
Alias.IsValid(genericStructItem, out outputError);
这不是泛型的工作方式。您需要找到另一种方法来调用IsValid
,例如反射或向结构添加一个公共接口。
此外,我强烈地考虑使用类而不是结构。我不知道你选择structs的原因,但总的来说,不使用structs有几个原因,尤其是当它们需要可变时。