简体   繁体   English

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

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

Ok so I'm currently working with a set of classes that I don't have control over in some pretty generic functions using these objects. 好的,所以我目前正在使用一些类,这些类在我使用这些对象的一些通用函数中无法控制。 Instead of writing literally tens of functions that essentially do the same thing for each class I decided to use a generic function instead. 我决定编写一个泛型函数,而不是编写实际上每个类都做相同事情的数十个函数。

Now the classes I'm dealing with are a little weird in that the derived classes share many of the same properties but the base class that they are derived from doesn't. 现在,我正在处理的类有点怪异,因为派生类共享许多相同的属性,但派生自它们的基类却没有。 One such property example is .Parent which exists on a huge number of derived classes but not on the base class and it is this property that I need to use. 一个这样的属性示例是.Parent,它存在于大量派生类中,但不存在于基类中,我需要使用此属性。

For ease of understanding I've created a small example as follows: 为了便于理解,我创建了一个小示例,如下所示:

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

}

In the above example calling DoSomething() will throw the NotImplemented Exception in the base class's implementation of GetParent(), even though I'm forcing the cast to T which is a StandardDerivedClass. 在上面的示例中,即使我强制将强制类型转换为T(即StandardDerivedClass),调用DoSomething()也会在GetParent()的基类实现中引发NotImplemented Exception。

This is contrary to other casting behaviour where by downcasting will force the use of the base class's implementation. 这与其他转换行为相反,在其他转换行为中,通过向下转换将强制使用基类的实现。

I see this behaviour as a bug. 我将此行为视为错误。 Has anyone else out there encountered this? 还有其他人遇到过这个吗?

I see this behaviour as a bug. 我将此行为视为错误。

This behavior is correct. 此行为是正确的。 Since your method DoSomething is constraining T to StandardBaseClass , you only have access to the specific methods of StandardBaseClass , not any methods or properties of a derived class. 由于您的方法DoSomethingT限制为StandardBaseClass ,因此您只能访问StandardBaseClass的特定方法,而不能访问派生类的任何方法或属性。 Since StandardBaseClass does not have a Parent property, this is invalid, and should be invalid, by design. 由于StandardBaseClass没有Parent属性,因此在设计上这是无效的,并且应该无效。

There are two potential options here - You can use reflection to pull out the Parent property, or use C# 4's dynamic type, and treat this as a dynamic object. 这里有两个潜在的选择-您可以使用反射来拉出Parent属性,或者使用C#4的动态类型,并将其视为动态对象。 Both bypass the standard type checking in the compiler, however, so will require you to do extra type checking at runtime to verify that the Parent property exists. 但是,两者都绕过了编译器中的标准类型检查,因此,您将需要在运行时进行额外的类型检查,以验证Parent属性是否存在。

Create an interface that contains the Parent property. 创建一个包含Parent属性的接口。 Have each class that has a Parent property implement that interace. 让每个具有Parent属性的类都实现该接口。 You will then be able to create a generic method that accepts a parameter of type IHaveParent , and it will do the right thing. 然后,您将能够创建一个接受类型为IHaveParent的参数的通用方法,它将做正确的事情。

For anyone that is interested an succinct answer to this situation is answered by Stephen Cleary on msdn here: 对于对此情况有一个简洁答案的任何人,Stephen Cleary都会在msdn上回答:

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

To me this is a divergence in the class hierarchy. 对我来说,这是类层次结构上的分歧。 By this this I mean that either the base class has parent, or the derived classes with Parent are derived from an abstract child of the base. 我的意思是,要么基类有父级,要么派生类具有Parent都派生自基层的抽象子级。

Lol as John says, an interface as opposed to an abstract class is sufficient too. 约翰所说,哈哈,与抽象类相对的接口也足够。

You idea won't work because the compiler can never guarantee that the base class actually would have such a property. 您的想法将行不通,因为编译器永远无法保证基类实际上具有此类属性。 And it won't just select the "right" one based on if it has it or not. 而且,它不会仅仅根据是否具有“正确”来选择它。

The only way you can do this is using reflection and then test at runtime if the requested property exists on the inspected class. 做到这一点的唯一方法是使用反射,然后在运行时进行测试,如果所检查的类上存在所请求的属性。 You have to judge yourself if that is a viable way to do for your project (reflection is slow and requires maximum rights). 您必须判断自己是否对项目可行(反射缓慢且需要最大权限)。

This is correct, as the compiler only knows that it can bind to your type as a StandardBaseClass . 这是正确的,因为编译器只知道它可以绑定到你的类型作为StandardBaseClass The binding is not done at runtime (where it could potentially decide to use the StandardDerivedClass overload. 绑定不会在运行时完成(绑定可能会决定使用StandardDerivedClass重载。

If you know that it's a StandardDerivedClass , then why not just cast it as such? 如果您知道它是一个StandardDerivedClass ,那么为什么不就这样强制转换它呢?

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

It's a bit ugly, but you can accomplish this using a Registration system, where you register delegates for different possible derived classes that expose the 'shared' property/method and then use something like a Dictionary<Type,Func<SomeT>> to store the delegates. 这有点丑陋,但是您可以使用注册系统来完成此任务,在该系统中,您可以为暴露“共享”属性/方法的各种可能的派生类注册委托,然后使用Dictionary<Type,Func<SomeT>>进行存储代表们。 If you know all of the derived types ahead of time and don't have to load plug-ins or the like, you can also use the classic ugly if/else-if structure. 如果您提前知道所有派生类型,而不必加载插件等,则也可以使用经典的丑陋if / else-if结构。 Either way you're basically creating your own substitute for what should have been supported by the virtual method table. 无论哪种方式,您基本上都可以创建自己的替代方法,以替代虚拟方法表应支持的功能。

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

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