Есть ли «анонимный» общий тег в C#, как '?' на Java?
Вопрос
В Java можно объявить переменную, параметризованную «неизвестным» универсальным типом, которая выглядит следующим образом:
Foo<?> x;
Существует ли конструкция, эквивалентная этому вопросительному знаку, в C#?
Решение
Короткий ответ - нет.В C# нет эквивалентной функции.
Обходной путь от C# с точки зрения Java-разработчика автор Дэйр Обасанджо:
В некоторых случаях может потребоваться создать метод, который может работать со структурами данных, содержащими любой тип, а не со структурами, содержащими определенный тип (например,метод печати всех объектов в структуре данных), сохраняя при этом преимущества строгой типизации в дженериках.Механизм указания этого в C# осуществляется с помощью функции, называемой выводом универсального типа, тогда как в Java это делается с использованием подстановочных типов.Следующие примеры кода показывают, как оба подхода приводят к одному и тому же результату.
Код С#
using System;
using System.Collections;
using System.Collections.Generic;
class Test{
//Prints the contents of any generic Stack by
//using generic type inference
public static void PrintStackContents<T>(Stack<T> s){
while(s.Count != 0){
Console.WriteLine(s.Pop());
}
}
public static void Main(String[] args){
Stack<int> s2 = new Stack<int>();
s2.Push(4);
s2.Push(5);
s2.Push(6);
PrintStackContents(s2);
Stack<string> s1 = new Stack<string>();
s1.Push("One");
s1.Push("Two");
s1.Push("Three");
PrintStackContents(s1);
}
}
Java-код
import java.util.*;
class Test{
//Prints the contents of any generic Stack by
//specifying wildcard type
public static void PrintStackContents(Stack<?> s){
while(!s.empty()){
System.out.println(s.pop());
}
}
public static void main(String[] args){
Stack <Integer> s2 = new Stack <Integer>();
s2.push(4);
s2.push(5);
s2.push(6);
PrintStackContents(s2);
Stack<String> s1 = new Stack<String>();
s1.push("One");
s1.push("Two");
s1.push("Three");
PrintStackContents(s1);
}
}
Другие советы
AFAIK вы не можете сделать это на С#.Что делает BCL, и существует множество примеров, так это создание класса, который не является универсальным, а затем создание универсального класса, который наследует базовое поведение от предыдущего.См. пример ниже.
class Foo
{
}
class Foo<T> : Foo
{
}
Вы можете написать что-то вроде этого:
Foo t = new Foo<int>();
Хотя, по общему признанию, это не самый чистый подход, использование Foo<object> x
тоже может подойти.
В C# нет эквивалентного синтаксиса.
Это не (совсем) правда, что в C# нет эквивалента.Не существует статического эквивалента, который вы могли бы использовать в качестве типа или вызывать методы, это правда.Для этого используйте Ответ Хорхе.
С другой стороны, иногда для размышления нужна эквивалентная идея, и эквивалент там есть.Если у вас есть:
interface IFoo<T>
{
T Bar(T t, int n);
}
вы можете получить Type
который представляет IFoo<int>
с использованием typeof(IFoo<int>)
.Менее известный и частичный ответ на ваш вопрос заключается в том, что вы также можете получить Type
который представляет IFoo<T>
с использованием typeof(IFoo<>)
.
Это полезно, если вы хотите использовать IFoo<T>
для некоторых T
через размышления и не узнаю T
до времени выполнения.
Type theInterface = typeof(IFoo<>);
Type theSpecificInterface = theInterface.MakeGenericType(typeof(string));
// theSpecificInterface now holds IFoo<string> even though we may not have known we wanted to use string until runtime
// proceed with reflection as normal, make late bound calls / constructions, emit DynamicMethod code, etc.
Нет, в C# такой концепции нет.Вам нужно будет сослаться на базовый класс Foo (возможно, не универсальный Foo) или сделать метод, с которым вы работаете, универсальным (чтобы вы могли ссылаться на Foo и позволить вызывающему объекту вашего метода определить, что такое T является).
Надеюсь, это поможет.