C# : Passing a Generic Object
Solution 1
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);
}
Solution 2
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 aboutT
at the moment, so the compiler can't find a member calledT
Options:
Put a property in the
ITest
interface, and changePrintGeneric
to constrainT
: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
Solution 3
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.
Solution 4
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.
Solution 5
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
Related videos on Youtube
user1229895
Updated on April 01, 2020Comments
-
user1229895 about 4 years
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); } }
-
Ash Burlaczenko about 12 years
var
cannot be a variable name as it is a keyword. Can you show your actual code. -
mmx about 12 years@AshBurlaczenko Not correct.
var
is a contextual keyword added in C# 3.0. You can use it as an identifier name. Similarly, you can useyield
,select
,from
, etc. as identifier names in most contexts. -
user1229895 about 12 yearsactually "var" did work without using just Console.WriteLine...but that was my bad to use a keyword as a identifier name...
-
Péter Török about 12 yearsIn 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.
-
user1229895 about 12 yearshaha sorry I'll try to do so in the future. thx!
-
-
mmx about 12 yearsThis will not work,
ITest
does not have a member namedvar
. -
Alexander R about 12 yearsOnly going to work if ITest specifies the property var, of course. I'm not sure it does in the example.
-
user1229895 about 12 yearsi 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
-
mmx about 12 yearsSee my reply on Ash's comment to the question. You can use
var
as identifier name, just likeyield
, etc., though that's probably not a great idea. It's a contextual keyword. Tryint var;
to verify for yourself. -
Moo-Juice about 12 years@MehrdadAfshari, ah.. I was not aware of that. Well, today I learned. But yes, it's not something I'd ever actually do :)
-
Steve about 12 yearsTypo in your second code snippet there Jon? You said remove generics but there's still a <T> on the method?
-
user1229895 about 12 yearsI 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
-
Jon Skeet about 12 years@SteveHaigh: Doh, that's what I get for typing and talking on the phone at the same time. Fixed, thanks.
-
jonnystoten about 12 yearsOh yeah, you need to then change the fields to be properties in the implementing classes. Updated my answer to show you.
-
user1229895 about 12 yearstrying 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?
-
Jon Skeet about 12 years@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. -
user1229895 about 12 yearsi 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"
-
user1229895 about 12 yearsok, 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
-
Ozkan almost 4 yearsAs far as I know dynamic types are not recommended for basic functionalities like this. It should be your last resort.
-
Jon Skeet almost 4 years@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.