0

我有这个 C# WinForms 代码,其中我有几个不同structs的,所有功能都以相同的方式。因此,我没有编写单独的函数来添加或删除项目,而是尝试使用模板。

例如,这是一个structList<>我用来存储它的对应的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具有相同设置的功能,所以重复编写相同的代码似乎很愚蠢,以防我在这里不使用模板......

4

3 回答 3

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);
于 2013-02-05T16:49:06.480 回答
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];
    }
}
于 2013-02-05T16:51:42.563 回答
0

C# 泛型与 C++ 中的模板有很大不同,尽管语法看起来很相似。

当你说

T.IsValid(genericStructItem, out outputError);

听起来您希望编译器替换TAlias给您

Alias.IsValid(genericStructItem, out outputError);

这不是泛型的工作方式。您需要找到另一种调用方式IsValid,例如反射或向结构添加通用接口。

我也强烈考虑使用类而不是结构。我不知道你选择结构的原因,但一般来说有几个使用结构的原因,特别是如果它们需要是可变的。

于 2013-02-05T17:01:58.440 回答