SoftwareNinja
SoftwareNinja

Reputation: 1

C# method generics with class implementing interface

UPDATE: This does not work the way I was hoping it would so, as others have stated below, this is not really a valid approach. Will be handling what I need another way.

I've created an interface with a method using a generic parameter, and a class that implements it. But in the class implementation, I get an error that the class doesn't implement a member that is on the class. Which seems odd.

interface InterfaceA
{
    String MethodA<T>(T obj);
}

public class ClassA : InterfaceA
{
    public String name { get; set; }

    public ClassA()
    {
        this.name = "My Name";
    }

    public String MethodA<ClassA>(ClassA aClass)
    {
        String result = aClass.name;    //ERROR IS ON THIS LINE
        return result;
    }   
}

public class ClassB : InterfaceA
{
    public String test1 { get; set; }

    public ClassB()
    {
        this.test1 = String.Empty;
    }

    public String MethodA<ClassB>(ClassB obj)
    {
        String result = obj.test1;
        return result;
    }
}

public class ClassC : InterfaceA
{
    public String test2 { get; set; }

    public ClassC()
    {
        this.test2 = String.Empty;
    }

    public String MethodA<ClassC>(ClassC obj)
    {
        String result = obj.test2;
        return result;
    }
}

This gives "Error CS1061 'ClassA' does not contain a definition for 'name' and no accessible extension method 'name' accepting a first argument of type 'ClassA' could be found (are you missing a using directive or an assembly reference?)"

I'm sure I've got something wrong here but I'm not sure what it is.

Upvotes: 0

Views: 852

Answers (3)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112279

If in a given class you always want to call the method with the same parameter type, the solution is to add the generic type parameter to the interface instead:

interface InterfaceA<T>
{
    String MethodA(T obj);
}

Then you can implement it like this

public class ClassA : InterfaceA<ClassA>
{
    public String name { get; set; }

    public ClassA()
    {
        this.name = "My Name";
    }

    public String MethodA(ClassA aClass)
    {
        String result = aClass.name;    //No more error here.
        return result;
    }   
}

Upvotes: 0

DavidG
DavidG

Reputation: 118937

The problem is likely caused by you re-using the ClassA name for the generic type. In this case, that is hiding the real definition of ClassA. So, use another name for it, it's common to use T in C#. Now it could be any type, but if you want to make sure it has the name property, then you need a generic type constraint. For example, this would work:

interface InterfaceA
{
    string MethodA<T>(T obj) where T : ClassA;
                           //^^^^^^^^^^^^^^^^
}

public class ClassA : InterfaceA
{
    public String name { get; set; }

    public ClassA()
    {
        this.name = "My Name";
    }

    public string MethodA<T>(T aClass) where T : ClassA
                                     //^^^^^^^^^^^^^^^^

    {
        String result = aClass.name;
        return result;
    }
}

Of course, there's now a weird relationship between ClassA and InterfaceA so you may want to extract the name property out as it's own interface too. For example:

public interface INamed
{
    string name { get; }
}

Now your other code would look like this:

interface InterfaceA
{
    string MethodA<T>(T obj) where T : INamed;
                           //^^^^^^^^^^^^^^^^
}

public class ClassA : InterfaceA, INamed
{
    public String name { get; set; }

    public ClassA()
    {
        this.name = "My Name";
    }

    public string MethodA<T>(T aClass) where T : INamed
                                     //^^^^^^^^^^^^^^^^

    {
        String result = aClass.name;
        return result;
    }
}

Upvotes: 4

Flydog57
Flydog57

Reputation: 7111

Ignore the fact that you know that ClassA has a name property.

The compiler sees that MethodA is a member of InterfaceA (an interface that ClassA implements). That method is generic in type T, where T has no constraints. You are implementing MethodA with ClassA as the type parameter. You could have used any type. When you call the aClass.name getter, the compiler says "Hey, there are no contraints on T, you don't get to use any of its members".

To fix this, add an interface like:

public interface IHaveAName 
{
    string name {get;}
}

and then change your interface definition to:

interface InterfaceA
{
    String MethodA<T>(T obj) where T: IHaveAName;
}

Then declare that ClassA implements both interfaces:

public class ClassA : InterfaceA, IHaveAName

You may want to rethink what you are doing (my guess is that the reason you are doing this would be more apparently if this wasn't a dummied up example with meaningless names). It's hard to fathom why you have things structured this way given the information you have presented.

Upvotes: 2

Related Questions