我有这个C#WinForms代码,其中我有几个不同的structs
,它们都以相同的方式运行。因此,我没有编写单独的函数来添加或删除项目,而是尝试使用模板。
例如,这里有一个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
函数都有相同的设置,所以重复编写相同的代码似乎很愚蠢,以防我在这里不使用模板......
答案 0 :(得分:2)
你做不到。唯一的选择是将您的泛型参数的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);
答案 1 :(得分:0)
您不能使用约束来告诉编译器您的对象上将存在静态方法。如果确实需要静态,则需要使用反射来调用方法:
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];
}
}
答案 2 :(得分:0)
C#generics 显着与C ++中的模板不同,尽管语法看起来很相似。
当你说
时T.IsValid(genericStructItem, out outputError);
听起来你希望编译器用T
替换Alias
给你
Alias.IsValid(genericStructItem, out outputError);
这不是泛型如何工作。您需要找到另一种方法来调用IsValid
,例如反射或为结构添加公共接口。
此外,我强烈考虑使用类而不是结构。我不知道你选择结构的原因,但一般来说有几个原因不使用结构,特别是如果它们需要是可变的。