2012-03-12 15 views
9

Chcę mieć ogólną funkcję drukowania ... PrintGeneric (T) ... w następującym przypadku, czego mi brakuje?C#: Przekazywanie ogólnego obiektu

Jak zawsze swoją pomoc/wgląd jest doceniana ...

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); 
    } 
} 
+1

'var' nie może być nazwą zmiennej, ponieważ jest to kluczowe. Czy możesz pokazać swój faktyczny kod? –

+3

@AshBurlaczenko Nie zgadza się. 'var' to kontekstowe słowo kluczowe dodane w C# 3.0. Możesz użyć go jako nazwy identyfikatora. Podobnie możesz użyć 'yield',' select', 'z', itp. Jako nazw identyfikatorów w większości kontekstów. –

+0

faktycznie "var" działał bez używania tylko Console.WriteLine ... ale to było złe, gdy użyłem słowa kluczowego jako nazwy identyfikatora ... – user1229895

Odpowiedz

19

Nie kompiluje się, ponieważ T może być cokolwiek, a nie wszystko będzie miało pole myvar.

Można zrobić myvar nieruchomości na ITest:

public ITest 
{ 
    string myvar{get;} 
} 

i wdrożyć go na zajęciach jako właściwość:

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

a następnie umieścić rodzajowe ograniczenie na metodę:

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

ale w tym przypadku, szczerze mówiąc, lepiej ci st przechodząc w iTest:

public void PrintGeneric(ITest test) 
{ 
    Console.WriteLine("Generic : " + test.myvar); 
} 
+0

Dodałem właściwość do ITest, ale następnie mówi mi, że muszę go zaimplementować w MyClass1/MyClass2 ... co ma sens, ale potem pojawia się błąd, mówiąc, że zawiera już definicję dla myvar – user1229895

+0

O tak, musisz wtedy zmienić pola, aby były właściwościami w wdrażanie klas. Zaktualizowałem moją odpowiedź, aby pokazać ci. – jonnystoten

+0

Próbowałem PrintGeneric (test2) w głównym dla ogólnego i otrzymuję "Tylko przydział, wywołanie, inkrementacja, dekrementacja używana jako instrukcja" i PrintGeneric (test1) dla PrintGeneric (test ITest). .i dostaniesz "Wymagane jest odniesienie do obiektu dla pola niestatycznego" – user1229895

0

spróbować

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

jak @Ash Burlaczenko powiedział, nie można nazwać zmienną po słowo kluczowe, jeśli chcemy to reallllly prefiks z symbolem @, aby uniknąć słowa kluczowego

+1

To nie zadziała, 'ITest' nie ma członka o nazwie' var'. –

+0

Działa tylko w przypadku, gdy ITest określa właściwość var, oczywiście. Nie jestem pewien, czy tak jest w tym przykładzie. –

+0

tak, twoje prawo to musi zostać dodane do ITest również –

2

W swojej ogólnej metodzie T jest po prostu symbolem zastępczym dla typu. Jednak kompilator sam w sobie nic nie wie o konkretnym typie (typach) aplikacji, więc nie może założyć, że będzie miał element var.

Zwykłym sposobem obejścia tego celu jest dodanie rodzajowe typu ograniczenie do deklaracji metody, aby upewnić się, że typy używane wdrożyć specjalny interfejs (w przypadku, może to być ITest):

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

Następnie członkowie tego interfejsu będą bezpośrednio dostępni w metodzie. Jednak twój ITest jest obecnie pusty, musisz zadeklarować tam wszystkie rzeczy, aby umożliwić jego użycie w ramach metody.

2

Będziesz musiał dostarczyć więcej informacji na temat leków generycznych typu T. W twojej obecnej metodzie PrintGeneric, T może równie dobrze być string, która nie ma członu var.

Możesz zmienić var do właściwości zamiast pola

public interface ITest 
{ 
    string var { get; } 
} 

i dodać ograniczenie where T: ITest metody PrintGeneric.

6

Brakuje co najmniej kilka rzeczy:

  • ile używasz refleksji, argumenty typu muszą być znane w czasie kompilacji, więc nie można użyć

    PrintGeneric<test2.GetType()> 
    

    ... chociaż w tym przypadku nie trzeba i tak

  • PrintGeneric nie wie nic o T w tej chwili wiemy, więc kompilator C An't znaleźć członkiem nazywa T

Opcje:

  • Put nieruchomości w interfejsie ITest i zmienić PrintGeneric ograniczyć T:

    public void PrintGeneric<T>(T test) where T : ITest 
    { 
        Console.WriteLine("Generic : " + test.PropertyFromInterface); 
    } 
    
  • Put właściwość w interfejsie ITest i całkowicie usunąć generyczne:

    public void PrintGeneric(ITest test) 
    { 
        Console.WriteLine("Property : " + test.PropertyFromInterface); 
    } 
    
  • Zastosowanie dynamicznego typowania zamiast generycznych, jeśli używasz C# 4

+1

Typo w twoim drugim fragmencie kodu Jona? Powiedziałeś, że chcesz usunąć generyczne, ale nadal istnieje metoda ? –

+2

@SteveHaigh: Doh, to jest to, co dostaję za pisanie i rozmowę przez telefon w tym samym czasie. Naprawiono, dzięki. –

+0

próbuje pierwszej opcji ... Dodaję "string myvar {get;}" do ITest ... , ale otrzymuję komunikat o błędzie mówiąc, że MyClass1/MyClass2 nie implementuje członka interfejsu "ITest.myvar" ... dodając "string myvar {get;} "do MyClass1/MyClass2 powoduje błąd kompilacji mówiąc, że jest już zdefiniowany? – user1229895

1

Trzeba zdefiniować coś w interfejsie, takich jak:

public interface ITest 
{ 
    string Name { get; } 
} 

Implementacja ITest w twoim c dziewczęta:

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

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

Następnie ograniczają swój ogólny Print funkcję, aby ITest:

public void Print<T>(T test) where T : ITest 
{ 
} 
+0

Zobacz moją odpowiedź na komentarz Asha do pytania. Możesz użyć 'var' jako nazwy identyfikatora, tak jak' yield', itp., Ale to prawdopodobnie nie jest świetny pomysł. Jest to słowo kluczowe kontekstualne. Spróbuj 'int var;', aby zweryfikować samodzielnie. –

+0

@MehrdadAfshari, ah .. Nie wiedziałem o tym. Cóż, dzisiaj się nauczyłem. Ale tak, to nie jest coś, co kiedykolwiek robiłem :) –

Powiązane problemy