【问题标题】:Accessing property of generic type in a function in c#在c#的函数中访问泛型类型的属性
【发布时间】:2021-01-18 14:33:48
【问题描述】:

我需要一个具有通用方法的接口。但是,该接口的每个实现都会知道它的类型。

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

由于某种原因,当我以上述方式执行此操作时,它不起作用并声明:

“SpecificContext”不包含“MyProperty”的定义,并且找不到接受“SpecificContext”类型的第一个参数的可访问扩展方法“MyProperty”(您是否缺少 using 指令或程序集引用?)

为什么会发生这种情况以及如何解决?

我可以通过像这样移动泛型类型的定义来修复它:

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

但这会在代码的其他部分中断并且行不通。

编辑:我的代码的简化

【问题讨论】:

  • SpecificContext in GetValueFromSpecificContext&lt;SpecificContext&gt;(BaseContext&lt;SpecificContext&gt; my) 不代表类 SpecificContext。但它只是表示与常见通用声明中的T 相同的通用类型。当您调用该方法时,会提供此方法的实际类型。如obj.GetValueFromSpecificContext&lt;SpecificType&gt;(
  • 如果你的TGetValueFromSpecificContext 将只是SpecificContextSpecificContext 的任何派生类,那么你需要有如下方法.. int GetValueFromSpecificContext&lt;T&gt;(BaseContext&lt;T&gt; my) where T : SpecificContext; 这样你可以在方法体中访问MyProperty of my
  • @ChetanRanpariya 那么为什么第二种方法有效?很抱歉在发布后更改代码,但我能够简化很多。
  • 在第二种方法中,当您执行ISrvThatCantBeGeneric&lt;SpecificContext&gt; 时,您声明SrvThatCantBeGeneric 类将实现SpecificContext 类型的接口,这是特定类型而不是T

标签: c# generics


【解决方案1】:

通过写作:

public int GetValueFromSpecificContext<SpecificContext>(SpecificContext specificContext)

您“覆盖”范围,这里SpecificContext 是一个泛型类型参数,它掩盖了具有此名称的类,因此它与以下内容相同:

public int GetValueFromSpecificContext<T>(T specificContext)

也许你想写:

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

测试

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

输出

10

您还可以将接口和类提升为泛型,而不是方法本身

如果相关:

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

此外,如果您愿意或需要,您可以使用接口代替基类

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

非泛型类版本:

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

通用类版本:

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

【讨论】:

  • 接口的每个实现都会有完全不同的上下文。所以使用约束是行不通的。我需要寻找不同的方法来避免这个问题。
  • @Icen 答案已更新。要访问 MyProperty,您需要对基类或任何接口进行约束,如果您愿意的话。但 OOP 模式保持不变。
  • 我的目标是拥有可以从 ICO 容器中获取的步骤(功能)的强类型列表。在我们的过程中解决动态信号流的问题是一个非常好的主意。所以我喜欢 IStep1:ISrvThatCantBeGeneric 和 IStep2:ISrvThatCantBeGeneric ,然后 IOC 让我根据调用者的类型正确执行每个步骤。一切正常,除了您无法访问上下文对象,因为您不知道它的类型。
  • @Icen 很抱歉,我什么都不懂:我不知道你在这里用这个词汇描述的主题。但是似乎使用暴露的接口应该可以解决您的问题,因此您可以操作任何实现此接口的对象,而不管类层次结构如何,因此您可以访问MyProperty,不是吗?
  • 不幸的是,它不会因为每个客户的上下文对象完全不同。感谢您在我的设计中发现缺陷。这个想法根本行不通,我需要创造一些新的东西。
猜你喜欢
  • 1970-01-01
  • 2020-03-23
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2020-08-06
  • 1970-01-01
  • 2019-03-08
  • 1970-01-01
相关资源
最近更新 更多