繁体   English   中英

强制在C#中的泛型函数中调用派生类实现?

[英]Force calling the derived class implementation within a generic function in C#?

好的,所以我目前正在使用一些类,这些类在我使用这些对象的一些通用函数中无法控制。 我决定编写一个泛型函数,而不是编写实际上每个类都做相同事情的数十个函数。

现在,我正在处理的类有点怪异,因为派生类共享许多相同的属性,但派生自它们的基类却没有。 一个这样的属性示例是.Parent,它存在于大量派生类中,但不存在于基类中,我需要使用此属性。

为了便于理解,我创建了一个小示例,如下所示:

class StandardBaseClass {} // These are simulating the SMO objects

class StandardDerivedClass : StandardBaseClass {    
    public object Parent { get; set; }    
}

static class Extensions    
{    
        public static object GetParent(this StandardDerivedClass sdc) {
            return sdc.Parent;
        }

        public static object GetParent(this StandardBaseClass sbc)
        {
            throw new NotImplementedException("StandardBaseClass does not contain a property Parent");
        }

        // This is the Generic function I'm trying to write and need the Parent property.    
        public static void DoSomething<T>(T foo) where T : StandardBaseClass
        {
            object Parent = ((T)foo).GetParent();
        }

}

在上面的示例中,即使我强制将强制类型转换为T(即StandardDerivedClass),调用DoSomething()也会在GetParent()的基类实现中引发NotImplemented Exception。

这与其他转换行为相反,在其他转换行为中,通过向下转换将强制使用基类的实现。

我将此行为视为错误。 还有其他人遇到过这个吗?

我将此行为视为错误。

此行为是正确的。 由于您的方法DoSomethingT限制为StandardBaseClass ,因此您只能访问StandardBaseClass的特定方法,而不能访问派生类的任何方法或属性。 由于StandardBaseClass没有Parent属性,因此在设计上这是无效的,并且应该无效。

这里有两个潜在的选择-您可以使用反射来拉出Parent属性,或者使用C#4的动态类型,并将其视为动态对象。 但是,两者都绕过了编译器中的标准类型检查,因此,您将需要在运行时进行额外的类型检查,以验证Parent属性是否存在。

创建一个包含Parent属性的接口。 让每个具有Parent属性的类都实现该接口。 然后,您将能够创建一个接受类型为IHaveParent的参数的通用方法,它将做正确的事情。

对于对此情况有一个简洁答案的任何人,Stephen Cleary都会在msdn上回答:

http://social.msdn.microsoft.com/Forums/zh-CN/csharpgeneral/thread/95833bb3-fbe1-4ec9-8b04-3e05165e20f8?prof=required

对我来说,这是类层次结构上的分歧。 我的意思是,要么基类有父级,要么派生类具有Parent都派生自基层的抽象子级。

约翰所说,哈哈,与抽象类相对的接口也足够。

您的想法将行不通,因为编译器永远无法保证基类实际上具有此类属性。 而且,它不会仅仅根据是否具有“正确”来选择它。

做到这一点的唯一方法是使用反射,然后在运行时进行测试,如果所检查的类上存在所请求的属性。 您必须判断自己是否对项目可行(反射缓慢且需要最大权限)。

这是正确的,因为编译器只知道它可以绑定到你的类型作为StandardBaseClass 绑定不会在运行时完成(绑定可能会决定使用StandardDerivedClass重载。

如果您知道它是一个StandardDerivedClass ,那么为什么不就这样强制转换它呢?

object Parent = ((StandardDerivedClass)foo).Parent;

这有点丑陋,但是您可以使用注册系统来完成此任务,在该系统中,您可以为暴露“共享”属性/方法的各种可能的派生类注册委托,然后使用Dictionary<Type,Func<SomeT>>进行存储代表们。 如果您提前知道所有派生类型,而不必加载插件等,则也可以使用经典的丑陋if / else-if结构。 无论哪种方式,您基本上都可以创建自己的替代方法,以替代虚拟方法表应支持的功能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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