C# 模板选项
C# Template options
我正在尝试做一些可以在 C++ 中工作的东西,但 C# 对我来说有点挑战。
我有一个方法可以执行一些解析、数据库访问、web access/etc 并最终得到一系列要添加到容器中的字符串。有时我需要将它添加到哈希集或列表等。
所以,在 C++ 中,这看起来像这样:
<template T>
bool GetStrings(T& container)
{
...
std::string foo = "bar";
...
container.add(foo); // This statement is within a loop and if checks
...
return true;
}
我在 C# 中尝试过:
private bool GetStrings<T>(ref T cont)
{
string foo = "BAR";
cont.Add(foo); // T does not contain a definition for Add ...
return true;
}
一位同事建议改用容器的基础 class/interface。所以,我尝试了这个(在看到 List、Hashset 等有一个共同的接口定义之后):
private bool GetStrings(ref ICollection<string> cont)
{
string foo = "BAR";
cont.Add(foo);
return true;
}
我希望能够像这样调用此方法:
HashSet<string> a = new HashSet<string>();
List<string> b = new List<string>();
// etc other classes containing "Add" method
if (GetString(ref a)) ... // These aren't all in one place, but spread out
if (GetString(ref b)) ... // and the types are based on what is useful in
if (GetString(ref c)) ... // each particular context.
if (GetString(ref d)) ...
现在方法本身可以编译,但我无法调用它。我得到 Best overload has invalid arguments, "Argument 1: cannot convert from 'ref System.Collections.Generic.List' to 'ref System.Collections.Generic.ICollection'"
我认为它只是一个需要类型转换的东西。所以,我试试 :
if (GetString(ref (ICollection<string>)a)) ...
然后我得到"A ref or out argument must be an assignable variable"。所以,问题是……这可以在 C# 中完成吗,我是不是完全走错了路?我还研究了传递 Object ref 并尝试调用 'GetType' 和 'GetMethod' 等来确定 Add 是否可用等等,但无法弄清楚如何调用 Add 方法。
您需要对您的方法使用通用约束:
private bool GetStrings<T>(T cont) where T : ICollection<string>
{
string foo = "BAR";
// The compiler knows that T is always ICollection<string>, and can infer that Add
// is a valid method call
cont.Add(foo);
return true;
}
此外,您不需要通过引用传递列表 - 它已经是一个引用。用 C++ 的说法,这就像你传递一个指向那里的指针的指针。
使用generic type constraints。
您可以执行以下编译并运行的操作:
class Program
{
static void Main(string[] args)
{
Test t = new Test();
HashSet<string> a = new HashSet<string>();
List<string> b = new List<string>();
if (t.GetString(ref a))
{
}
if (t.GetString(ref b))
{
}
}
public class Test
{
public bool GetString<T>(ref T cont) where T : ICollection<string>
{
string foo = "BAR";
cont.Add(foo);
return true;
}
}
}
顺便说一句,所有的集合都已经是引用类型了,除非你想改变原来的变量,ref是不需要的。参见 here for an explanation。
我正在尝试做一些可以在 C++ 中工作的东西,但 C# 对我来说有点挑战。
我有一个方法可以执行一些解析、数据库访问、web access/etc 并最终得到一系列要添加到容器中的字符串。有时我需要将它添加到哈希集或列表等。
所以,在 C++ 中,这看起来像这样:
<template T>
bool GetStrings(T& container)
{
...
std::string foo = "bar";
...
container.add(foo); // This statement is within a loop and if checks
...
return true;
}
我在 C# 中尝试过:
private bool GetStrings<T>(ref T cont)
{
string foo = "BAR";
cont.Add(foo); // T does not contain a definition for Add ...
return true;
}
一位同事建议改用容器的基础 class/interface。所以,我尝试了这个(在看到 List、Hashset 等有一个共同的接口定义之后):
private bool GetStrings(ref ICollection<string> cont)
{
string foo = "BAR";
cont.Add(foo);
return true;
}
我希望能够像这样调用此方法:
HashSet<string> a = new HashSet<string>();
List<string> b = new List<string>();
// etc other classes containing "Add" method
if (GetString(ref a)) ... // These aren't all in one place, but spread out
if (GetString(ref b)) ... // and the types are based on what is useful in
if (GetString(ref c)) ... // each particular context.
if (GetString(ref d)) ...
现在方法本身可以编译,但我无法调用它。我得到 Best overload has invalid arguments, "Argument 1: cannot convert from 'ref System.Collections.Generic.List' to 'ref System.Collections.Generic.ICollection'"
我认为它只是一个需要类型转换的东西。所以,我试试 :
if (GetString(ref (ICollection<string>)a)) ...
然后我得到"A ref or out argument must be an assignable variable"。所以,问题是……这可以在 C# 中完成吗,我是不是完全走错了路?我还研究了传递 Object ref 并尝试调用 'GetType' 和 'GetMethod' 等来确定 Add 是否可用等等,但无法弄清楚如何调用 Add 方法。
您需要对您的方法使用通用约束:
private bool GetStrings<T>(T cont) where T : ICollection<string>
{
string foo = "BAR";
// The compiler knows that T is always ICollection<string>, and can infer that Add
// is a valid method call
cont.Add(foo);
return true;
}
此外,您不需要通过引用传递列表 - 它已经是一个引用。用 C++ 的说法,这就像你传递一个指向那里的指针的指针。
使用generic type constraints。 您可以执行以下编译并运行的操作:
class Program
{
static void Main(string[] args)
{
Test t = new Test();
HashSet<string> a = new HashSet<string>();
List<string> b = new List<string>();
if (t.GetString(ref a))
{
}
if (t.GetString(ref b))
{
}
}
public class Test
{
public bool GetString<T>(ref T cont) where T : ICollection<string>
{
string foo = "BAR";
cont.Add(foo);
return true;
}
}
}
顺便说一句,所有的集合都已经是引用类型了,除非你想改变原来的变量,ref是不需要的。参见 here for an explanation。