C #: прохождение общего объекта - PullRequest
14 голосов
/ 12 марта 2012

Я хочу иметь общую функцию печати ... PrintGeneric (T) ... в следующем случае, что мне не хватает?

Как всегда, ваша помощь / понимание приветствуется ...

public interface ITest
{}

public class MyClass1 : ITest
{
    public string myvar = "hello 1";
}

public class MyClass2 : ITest
{
    public string myvar = "hello 2";
}

class DoSomethingClass
{

    static void Main()
    {
        MyClass1 test1 = new MyClass1();
        MyClass2 test2 = new MyClass2();

        Console.WriteLine(test1.myvar);
        Console.WriteLine(test2.myvar);             
        Console.WriteLine(test1.GetType());

        PrintGeneric(test1);
        PrintGeneric<test2.GetType()>(test2);
    }

    // following doesn't compile
    public void PrintGeneric<T>(T test)
    {
        Console.WriteLine("Generic : " + test.myvar);
    }
}

Ответы [ 7 ]

24 голосов
/ 12 марта 2012

Он не компилируется, потому что T может быть чем угодно, и не у всех будет поле myvar.

Вы можете сделать myvar свойством ITest:

public ITest
{
    string myvar{get;}
}

и реализуйте его на классах как свойство:

public class MyClass1 : ITest
{
    public string myvar{ get { return "hello 1"; } }
}

, а затем наложите общее ограничение на ваш метод:

public void PrintGeneric<T>(T test) where T : ITest
{
    Console.WriteLine("Generic : " + test.myvar);
}

но в этом случае, если честно, вылучше просто пройти в ITest:

public void PrintGeneric(ITest test)
{
    Console.WriteLine("Generic : " + test.myvar);
}
6 голосов
/ 12 марта 2012

Вам не хватает хотя бы пары вещей:

  • Если вы не используете отражение, аргументы типа должны быть известны во время компиляции, поэтому вы не можетеиспользуйте

    PrintGeneric<test2.GetType()>
    

    ... хотя в этом случае вам все равно не нужно

  • PrintGeneric ничего не знает о T вмомент, поэтому компилятор не может найти элемент с именем T

Опции:

  • Поместить свойство в интерфейс ITestи измените PrintGeneric на ограничение T:

    public void PrintGeneric<T>(T test) where T : ITest
    {
        Console.WriteLine("Generic : " + test.PropertyFromInterface);
    }
    
  • Поместите свойство в интерфейс ITest и полностью удалите обобщенные значения:

    public void PrintGeneric(ITest test)
    {
        Console.WriteLine("Property : " + test.PropertyFromInterface);
    }
    
  • Используйте динамическую типизацию вместо универсальных, если вы используете C # 4

2 голосов
/ 12 марта 2012

Вам нужно будет предоставить больше информации об универсальном типе T. В вашем текущем методе PrintGeneric, T также может быть string, в котором нет члена var.

Возможно, вы захотите изменить var на свойство, а не на поле

public interface ITest
{
    string var { get; }
}

И добавить ограничение where T: ITest в метод PrintGeneric.

2 голосов
/ 12 марта 2012

В вашем родовом методе T - это просто заполнитель для типа.Однако компилятор сам по себе ничего не знает о конкретных типах, используемых во время выполнения, поэтому он не может предположить, что у них будет var член.

Обычный способ обойти этозаключается в добавлении ограничения общего типа в объявление вашего метода, чтобы гарантировать, что используемые типы реализуют определенный интерфейс (в вашем случае это может быть ITest):

public void PrintGeneric<T>(T test) where T : ITest

Затем члены этого интерфейсабудет непосредственно доступен внутри метода.Тем не менее, ваш ITest в настоящее время пуст, вам нужно объявить общие вещи там, чтобы включить его использование в методе.

1 голос
/ 12 марта 2012

Вам необходимо определить что-то в интерфейсе, например:

public interface ITest
{
    string Name { get; }
}

Реализация ITest в ваших классах:

public class MyClass1 : ITest
{
    public string Name { get { return "Test1"; } }
}

public class MyClass2 : ITest
{
    public string Name { get { return "Test2"; } }
}

Затем ограничьте вашу общую Print функцию ITest:

public void Print<T>(T test) where T : ITest
{
}
0 голосов
/ 12 марта 2012

Вы не можете получить доступ к var с помощью универсального.

Попробуйте что-то вроде

Console.WriteLine("Generic : {0}", test);

И переопределить ToString метод [1]

[1] http://msdn.microsoft.com/en-us/library/system.object.tostring.aspx

0 голосов
/ 12 марта 2012

1001 * попробовать *

public void PrintGeneric<T>(T test) where T: ITest
{
    Console.WriteLine("Generic : " + test.@var);
}

как @Ash Бурлаченко сказал, что вы не можете назвать переменную после ключевого слова, если вы действительно хотите, чтобы этот префикс с символом @ экранировал ключевое слово

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...