user1229895
user1229895

Reputation: 2319

C# : Passing a Generic Object

I want to have a generic print function...PrintGeneric(T)...in the following case, what am I missing?

As always your help/insight is appreciated...

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

Upvotes: 26

Views: 150718

Answers (7)

jonnystoten
jonnystoten

Reputation: 7133

It doesn't compile because T could be anything, and not everything will have the myvar field.

You could make myvar a property on ITest:

public ITest
{
    string myvar{get;}
}

and implement it on the classes as a property:

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

and then put a generic constraint on your method:

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

but in that case to be honest you are better off just passing in an ITest:

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

Upvotes: 32

Jon Skeet
Jon Skeet

Reputation: 1499770

You're missing at least a couple of things:

  • Unless you're using reflection, the type arguments need to be known at compile-time, so you can't use

    PrintGeneric<test2.GetType()>
    

    ... although in this case you don't need to anyway

  • PrintGeneric doesn't know anything about T at the moment, so the compiler can't find a member called T

Options:

  • Put a property in the ITest interface, and change PrintGeneric to constrain T:

    public void PrintGeneric<T>(T test) where T : ITest
    {
        Console.WriteLine("Generic : " + test.PropertyFromInterface);
    }
    
  • Put a property in the ITest interface and remove the generics entirely:

    public void PrintGeneric(ITest test)
    {
        Console.WriteLine("Property : " + test.PropertyFromInterface);
    }
    
  • Use dynamic typing instead of generics if you're using C# 4

Upvotes: 8

Moo-Juice
Moo-Juice

Reputation: 38825

You need to define something in the interface, such as:

public interface ITest
{
    string Name { get; }
}

Implement ITest in your classes:

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

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

Then restrict your generic Print function, to ITest:

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

Upvotes: 1

undefined
undefined

Reputation: 34238

try

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

as @Ash Burlaczenko has said you cant name a variable after a keyword, if you reallllly want this prefix with @ symbol to escape the keyword

Upvotes: 1

P&#233;ter T&#246;r&#246;k
P&#233;ter T&#246;r&#246;k

Reputation: 116246

In your generic method, T is just a placeholder for a type. However, the compiler doesn't per se know anything about the concrete type(s) being used runtime, so it can't assume that they will have a var member.

The usual way to circumvent this is to add a generic type constraint to your method declaration to ensure that the types used implement a specific interface (in your case, it could be ITest):

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

Then, the members of that interface would be directly available inside the method. However, your ITest is currently empty, you need to declare common stuff there in order to enable its usage within the method.

Upvotes: 2

nolith
nolith

Reputation: 613

You cannot access var with the generic.

Try something like

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

And override ToString method [1]

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

Upvotes: 0

C.Evenhuis
C.Evenhuis

Reputation: 26436

You'll have to provide more information about the generic type T. In your current PrintGeneric method, T might as well be a string, which does not have a var member.

You may want to change var to a property rather than a field

public interface ITest
{
    string var { get; }
}

And add a constraint where T: ITest to the PrintGeneric method.

Upvotes: 2

Related Questions