26

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);
    }
}
5
  • 1
    var cannot be a variable name as it is a keyword. Can you show your actual code. Commented Mar 12, 2012 at 9:57
  • 3
    @AshBurlaczenko Not correct. var is a contextual keyword added in C# 3.0. You can use it as an identifier name. Similarly, you can use yield, select, from, etc. as identifier names in most contexts. Commented Mar 12, 2012 at 9:59
  • 1
    actually "var" did work without using just Console.WriteLine...but that was my bad to use a keyword as a identifier name... Commented Mar 12, 2012 at 10:01
  • 2
    In this case we managed to guess successfully where your problem lied and what the error was. However, you shouldn't rely on our psychic powers too much ;-) In general, it makes everyone's life easier if you precisely indicate the code line where the error occurs, and post the exact error message too. Commented Mar 12, 2012 at 10:08
  • haha sorry I'll try to do so in the future. thx! Commented Mar 12, 2012 at 10:25

7 Answers 7

32

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);
}
Sign up to request clarification or add additional context in comments.

4 Comments

I added a property to ITest, but then it tells me I need to implement it in MyClass1/MyClass2...which makes sense, but then I get an error saying it already contains a definition for myvar
Oh yeah, you need to then change the fields to be properties in the implementing classes. Updated my answer to show you.
i tried PrintGeneric<test2.GetType()>(test2) in Main for the generic and get an 'Only assignment, call, increment, decrement used as a statement' and PrintGeneric(test1) for PrintGeneric(ITest test)..and get a "An object reference is required for non-static field"
ok, i see I see I need to change to 'public static void PrintGeneric(ITest test)'...still unsure why PrintGeneric<T> says only assignment/call/increment can be used as a statement
8

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

6 Comments

Typo in your second code snippet there Jon? You said remove generics but there's still a <T> on the method?
@SteveHaigh: Doh, that's what I get for typing and talking on the phone at the same time. Fixed, thanks.
trying the first option...I add "string myvar {get;}" to ITest... but get an error saying MyClass1/MyClass2 don't implement Interface member 'ITest.myvar'...adding "string myvar {get;}" to MyClass1/MyClass2 results in compile error saying its already defined?
@user1229895: You can't declare a concrete property like that... but that has nothing to do with generics. You can use an automatically implemented property to implement it in MyClass1 with public string myvar { get; private set; }. If that's not enough help, I suggest you ask a separate question.
@Ozkan: Well it is last in the list here... although I'd say that using dynamic typing instead of manually-written reflection can be useful to effectively offload the reflection code to a well-tested codebase.
|
2

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.

Comments

2

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.

Comments

1

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

3 Comments

This will not work, ITest does not have a member named var.
Only going to work if ITest specifies the property var, of course. I'm not sure it does in the example.
i get a number of errors... CS0120 : An Object Reference is Required for non-static field/method/property 'DoSomethingClass.PrintGeneric<T>(T) CS0201 : Only Assignment, call, increment, decrement, new object can be used as a statement CS0019 : operator < cannote be applied to operands of type Method Group CS1061 : T does not contain definition myvar
1

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
{
}

2 Comments

See my reply on Ash's comment to the question. You can use var as identifier name, just like yield, etc., though that's probably not a great idea. It's a contextual keyword. Try int var; to verify for yourself.
@MehrdadAfshari, ah.. I was not aware of that. Well, today I learned. But yes, it's not something I'd ever actually do :)
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.