2015-04-03 4 views
1

Я пытаюсь сделать что-то, что будет работать на C++, но C# для меня немного сложнее.C# Параметры шаблона

У меня есть метод, который выполняет немного разбора, доступа к базе данных, веб-доступа/etc и в конечном итоге заканчивается цепочкой строк для добавления в контейнер. Иногда мне нужно, чтобы добавить его в HashSet или списка или т.п.

Так, в 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; 
} 

A коллега предложил вместо этого использовать базовый класс/интерфейс контейнера. Итак, я попытался это (после просмотра списка, 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)) ... 

Теперь сам метод компилируется, но я не могу его вызывать. Я получаю лучшее от перегрузки имеет недопустимые аргументы, «Аргумент 1: не удается преобразовать из„иого System.Collections.Generic.List“до„иого System.Collections.Generic.ICollection“»

Я полагаю, что его просто приведение типа необходимая вещь. Итак, я стараюсь:

if (GetString(ref (ICollection<string>)a)) ... 

Тогда я получаю «реф или из аргументов должен быть назначаемая переменная». Итак, вопрос в том, может ли это быть сделано на C#, я просто полностью ошибаюсь? Я также рассмотрел передачу Object ref и попытался вызвать «GetType» и «GetMethod» и так, чтобы выяснить, доступен ли «Добавить», но не смог понять, как вызвать метод «Добавить».

ответ

1

Использование 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; 
     } 
    } 
} 

Кстати все коллекции уже ссылочные типы, если вы не хотите, чтобы изменить исходную переменную, реф не нужно. См. here for an explanation.

0

Вы должны использовать общие ограничения на ваш метод:

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++ это похоже на то, что вы передаете указатель на указатель.

Смежные вопросы