Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何从模板调用方法?_C#_Templates_Generics_Data Structures_Struct - Fatal编程技术网

C# 如何从模板调用方法?

C# 如何从模板调用方法?,c#,templates,generics,data-structures,struct,C#,Templates,Generics,Data Structures,Struct,我有一个C#WinForms代码,其中有几个不同的结构,它们都以相同的方式运行。因此,我不再编写用于添加或删除项的单个函数,而是尝试使用模板 例如,这里有一个struct和相应的列表,我用来存储它的对象: public struct Alias { public string alias; public string aliasSource; public static bool IsValid(...); //This function exists in all t

我有一个C#WinForms代码,其中有几个不同的
结构
,它们都以相同的方式运行。因此,我不再编写用于添加或删除项的单个函数,而是尝试使用模板

例如,这里有一个
struct
和相应的
列表
,我用来存储它的
对象

public struct Alias
{
    public string alias;
    public string aliasSource;

    public static bool IsValid(...); //This function exists in all the structs
};

List<Alias> aliases;

这有什么办法吗?我所有的
struct
都有一个
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);       
}

不能使用约束告诉编译器对象上将存在静态方法。如果确实需要是静态的,则需要使用反射来调用该方法:

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);
听起来您希望编译器将
T
替换为
Alias
以提供

Alias.IsValid(genericStructItem, out outputError);
这不是泛型的工作方式。您需要找到另一种方法来调用
IsValid
,例如反射或向结构添加公共接口


<>我也会强烈地考虑使用类而不是结构。我不知道选择结构的原因,但一般来说,不使用结构的原因有很多,尤其是如果它们需要是可变的。虽然语法看起来很相似,但是,

C泛型与C++中的模板有很大的不同。我希望一个名为IsValid()的方法需要访问该对象。是的,我想这是一种看待它的方式。不过,我使用它的方式是,当我需要验证输入本身时(以后创建结构实例时基于输入),因此需要事先进行验证,这就是为什么在这种情况下需要使用静态方法。您能告诉我您在
(…)
中放了什么吗?下面是我使用的完整行:
var isValid=(bool)methodInfo.Invoke(genericStructItem,out outputError),但这给了我一个错误:
与'System.Reflection.MethodBase.Invoke(object,object[])匹配的最佳重载方法有一些无效参数
,我将更新我的代码。此外,这篇文章还很好地解释了通过带有out参数的反射进行的静态方法调用:不确定该场景如何适合我的场景。我找到了需要放置什么来代替
object,object[]
,但我的问题是
out
参数不起作用(就像您指出的线程中的问题一样)。但是,该页面上的解决方案使用C#定义的函数来使用TryParse(即
getryparsemethodinfo()
),这是我无法做到的,因为
在我自己的函数中是有效的。应该行的,刚刚看到代码。看起来还可以,但我认为您已将
out
参数置零。难道不可能以某种方式将
部分也提取出来吗?这对于非静态方法很好,但不适用于静态方法。@itsme86请仔细阅读我答案的第一段
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];
    }
}
T.IsValid(genericStructItem, out outputError);
Alias.IsValid(genericStructItem, out outputError);