【问题标题】:How to create a generic interface of a method that returns a Type of a class that implements an interface?如何创建返回实现接口的类的类型的方法的通用接口?
【发布时间】:2012-07-24 11:06:30
【问题描述】:

我正在寻找一种在下面定义“MethodA”的方法,以便它返回一个类定义(System.Type),其中所述类型的一个实例实现了“InterfaceB”

interface IMyInterface
{
  TType MethodA<TType, TInterface>() 
    : where TType : System.Type
    : where [instanceOf(TType)] : TInterface
}

(注意:instanceOf 不是真实的,当然……)

我怀疑在编译时不可能得到这种验证。我希望有人能证明我错了。

提前感谢您的任何指导。

编辑:我已经更新了这个,希望更具体地返回一个 System.Type,后面的代码可以执行它:

var classType = myInterface.MethodA<(something, ISomeInterface)>();
ISomeInterface = new classType();  //--Assuming default constructor

我还没有真正专注于这部分,只是对我的主要问题的理论结构更加好奇。

【问题讨论】:

  • 将返回类型改为TInterface
  • 您是在使用“类型”来表示System.Type,还是表示您已定义的某种类型?在前一种情况下,由于显而易见的原因,您尝试做的事情是不可能的,而且您几乎肯定不应该从 System.Type 派生。
  • 是的,我的意思是 System.Type。我正在尝试查看是否可以获得实现 TInterface 的东西的类定义,稍后我将对其进行“更新”。我试图避免用这种特殊的方法来更新它。

标签: c# generics types interface


【解决方案1】:

您的问题有两种解释;一个是微不足道的,一个是不可能的,所以我会继续介绍两者。

  1. 您想返回一个实现System.TypeTInterface 的类型的实例。

    这很简单:只需使用 where TType : Typewhere TType : TInterface

  2. 您想要返回一个 System.Type 的实例,该实例表示继承自 TInterface 的类型。

    这是不可能在 .NET(和 C#)类型系统中指定的。

    类型系统只能解析来自类型层次结构本身的信息,但不能强制执行“合同”,例如受限的运行时属性值。关于默认构造函数等有一些技巧,但据我所知,甚至无法测试现有方法(例如,与 C++ 模板不同,更不用说 Qi 等人了)。

更新

请查看Michael Graczyk的评论。

另外:我刚刚发现 .NET 有代码合同检查器(静态和运行时):Microsoft DevLabs Code-Contracts for .NET。我从来没有使用过它们,甚至对它们都不陌生,但这看起来很有趣!

但是,即使不看,我也很确定重载解析等将无法使用此类信息。

【讨论】:

  • 3.他用“类型”这个词来表示System.Type以外的东西。
  • 你说得对。哎哟。对于其他读者:属于第 2 类。)检查属性值将不起作用。
  • 对于#1,我将其简化为 where TType : Type, TInterface
【解决方案2】:

在这种情况下:

// We have an interface...
interface InterfaceB {}

// And this class implements the interface.
class ImplementsB : InterfaceB {}

// But this class does not.
class DoesNotImplementB {}

您可以将MethodA 定义为:

static Type MethodA<TClass, TInterface>()
    where TClass : TInterface
{
    return typeof(TClass);
}

然后以下将起作用:

Type t = MethodA<ImplementsB, InterfaceB>();

但这会产生编译时错误:

Type t = MethodA<DoesNotImplementB, InterfaceB>();

类型“DoesNotImplementB”不能用作泛型类型或方法“MethodA()”中的类型参数“TClass”。没有从“DoesNotImplementB”到“InterfaceB”的隐式引用转换。

因此,这样您就可以确定MethodA 的结果是实现TInterface 的类的Type。鉴于 Type 对象,您可以稍后像这样实例化它:

public object Instantiate(Type type)
{
    // Call the default constructor.
    // You can change this to call any constructor you want.
    var constructor = type.GetConstructor(Type.EmptyTypes);
    var instance = constructor.Invoke(new object[0]);
    return instance;
}

如果您知道您的Type 与某些接口TInterface 兼容,那么您可以使用这样的附加方法来避免强制转换:

public TInterface Instantiate<TInterface>(Type type)
{
    return (TInterface)Instantiate(type);
}

但是,如果 typeType,但不知何故未实现 TInterface,您将在运行时获得 InvalidCastException。没有办法将Type 限制为在编译时实现特定接口的类型。但是,在运行时您可以检查它以避免InvalidCastException 异常:

public TInterface Instantiate<TInterface>(Type type)
{
    if (!typeof(TInterface).IsAssignableFrom(type))
        throw new Exception("Wrong type!");
    return (TInterface)Instantiate(type);
}

请注意,typeof(TType) 是一个产生Type 对象的表达式,因此无论您在哪里看到typeof(),您都可以将其替换为任何Type 变量,反之亦然。

这是你想知道的吗?

【讨论】:

  • 关闭,但我试图避免此时实际实例化对象。我想返回类定义本身,稍后我可以用它来实例化对象。我的问题是我想不出一种方法来保证返回的 (System.Type) 在实例化时实际上实现了 TInterface。至少,直到我尝试实例化它并将其转换为 TInterface。但这是一个运行时解决方案,而不是编译时解决方案。
  • 我更新了我的帖子。这更接近你想知道的吗?
  • 我没有忘记这一点,我只是没有时间应用你的想法。听起来不错,也许我这个周末有机会尝试一下,并在可能的情况下更新此评论块。
猜你喜欢
  • 2011-05-16
  • 2011-06-22
  • 2016-01-09
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
  • 2012-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多