简体   繁体   中英

Accessing property of generic type in a function in c#

I need to have a interface that has generic methods. However each implementation of that interface will know its type.

class Program
{
    static void Main(string[] args)
    {

        var specificContext = new SpecificContext();

        var res = new SrvThatCantBeGeneric().GetValueFromSpecificContext(specificContext);
        Console.WriteLine(res);
    }

}
public class SrvThatCantBeGeneric : ISrvThatCantBeGeneric
{
    public int GetValueFromSpecificContext<SpecificContext>(SpecificContext specificContext)
    {
        return specificContext.MyProperty; // <-- this is where it breaks
    }
}

public interface ISrvThatCantBeGeneric
{        
    int GetValueFromSpecificContext<T>( T specificContext);
}

public class SpecificContext
{
    public int MyProperty { get; set; } = 42;
}

For some reason when I do it the above way it doesn't work and states that:

'SpecificContext' does not contain a definition for 'MyProperty' and no accessible extension method 'MyProperty' accepting a first argument of type 'SpecificContext' could be found (are you missing a using directive or an assembly reference?)

Why is this happening and how to solve it?

I can fix it by moving definition of generic type like so:

public class SrvThatCantBeGeneric : ISrvThatCantBeGeneric<SpecificContext>
{
    public int GetValueFromSpecificContext(SpecificContext specificContext)
    {
        return specificContext.MyProperty; // <-- this is where it breaks
    }
}

public interface ISrvThatCantBeGeneric<T>
{        
    int GetValueFromSpecificContext( T specificContext);
}

but this breaks in another parts of code and is no go.

Edit: Simplification of my code

By writing:

public int GetValueFromSpecificContext<SpecificContext>(SpecificContext specificContext)

You "override" the scope and here SpecificContext is a generic type parameter that masks the class having this name, so it is the same as:

public int GetValueFromSpecificContext<T>(T specificContext)

Perhaps you wanted to write:

public interface ISrvThatCantBeGeneric
{
  int GetValueFromSpecificContext<T>(T specificContext) where T : SpecificContext;
}

public class SrvThatCantBeGeneric : ISrvThatCantBeGeneric
{
  public int GetValueFromSpecificContext<T>(T specificContext) where T : SpecificContext
  {
    return specificContext.MyProperty;
  }
}

public class SpecificContext
{
  public int MyProperty { get; set; } = 42;
}

public class SpecificContextChild : SpecificContext
{
  public SpecificContextChild()
  {
    MyProperty = 10;
  }
}

Test

var server = new SrvThatCantBeGeneric();
var context = new SpecificContextChild();
Console.WriteLine(server.GetValueFromSpecificContext(context));

Output

10

Also you can promote interface and class as generics, and not the method itself

In case it is relevant:

public interface ISrvThatCantBeGeneric<T> where T : SpecificContext
{
  int GetValueFromSpecificContext(T specificContext);
}

public class SrvThatCantBeGeneric<T> : ISrvThatCantBeGeneric<T> where T : SpecificContext
{
  public int GetValueFromSpecificContext(T specificContext)
  {
    return specificContext.MyProperty;
  }
}

public class SpecificContext
{
  public int MyProperty { get; set; } = 42;
}

public class SpecificContextChild : SpecificContext
{

  public SpecificContextChild()
  {
    MyProperty = 10;
  }
}

var server = new SrvThatCantBeGeneric<SpecificContextChild>();
var context = new SpecificContextChild();
Console.WriteLine(server.GetValueFromSpecificContext(context));

Also if you prefer or need you can use an interface instead of the base class

public interface IContext
{
  int MyProperty { get; set; }
}

Non-generic class version:

public interface ISrvThatCantBeGeneric
{
  int GetValueFromSpecificContext<T>(T specificContext) where T : IContext;
}

public class SrvThatCantBeGeneric : ISrvThatCantBeGeneric
{
  public int GetValueFromSpecificContext<T>(T specificContext) where T : IContext
  {
    return specificContext.MyProperty;
  }
}

public class SpecificContext : IContext
{
  public int MyProperty { get; set; } = 42;
}

Generic class version:

public interface ISrvThatCantBeGeneric<T> where T : IContext
{
  int GetValueFromSpecificContext(T specificContext);
}

public class SrvThatCantBeGeneric<T> : ISrvThatCantBeGeneric<T> where T : IContext
{
  public int GetValueFromSpecificContext(T specificContext)
  {
    return specificContext.MyProperty;
  }
}

public class SpecificContext : IContext
{
  public int MyProperty { get; set; } = 42;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM