将通用基础对象转换为派生类型

时间:2017-09-15 19:34:52

标签: c# generics inheritance casting

将使用泛型的基类强制转换为派生类型的正确方法是什么?

我实现了以下对象。

请注意,“Save”方法在此处调用“WriteSettings”方法(接受BaseSettings对象)

public class Settings1
{
    public string strData;
}

public class BaseSettings<T>
{
    T settings;
    public iSettingsDestination Destination;

    public bool Save()
    {
        return Destination.WriteSettings(this);
    }
}

public class Settings1Manager : BaseSettings<Settings1>
{
    public bool DoSomething()
    {
        return true;
    }
}

我创建了一个接口iSettingsDestination,它始终使用基类(BaseSettings)来传递对象。从iSettingsDestination派生的类可以选择要处理的对象类型。 我希望能够将此对象作为基类型传递给方法,确定派生类型,并反转强制转换。 (见下文)我在尝试强制转换为派生类型时收到编译错误。

public interface iSettingsDestination
{
    bool WriteSettings<T>(BaseSettings<T> settings);
}

public class FileDestination : iSettingsDestination
{
    bool WriteSettings1ManagerToFile(Settings1Manager settings)
    {
        // write to file
        return true;
    }

    bool WriteSettings<T>(BaseSettings<T> settings)
    {
        if (typeof(Settings1Manager).IsAssignableFrom(settings.GetType()))
        {
            // generates error
            // Cannot convert type 'BaseSettings<T>' to 'Settings1Manager'
            return WriteSettings1ManagerToNetwork((Settings1Manager)settings);
        }

        // unhandled object type
        return false;
    }

}

我希望能够像下面这样调用代码。对于此处的示例,我只显示1种类型的“目的地”和“设置”,但您可以想象这里可以使用许多不同的类型。

    void main()
    {
        Settings1Manager settings1 = new Settings1Manager();
        settings1.Destination = new FileDestination();
        settings1.Save(); // saves to a file
    }

我能够与其他基类一起使用,但似乎在这里使用泛型会导致问题。

1)如何在调用WriteSettings1ManagerToNetwork((Settings1Manager)设置中)正确地将强制转换回派生类型;

2)有没有人在这里看到任何明显滥用​​泛型/接口/等逻辑的问题?

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:4)

声明为BaseSettings<T> 的引用可能会或可能不会引用Settings1Manager的实际实例。这就是继承的工作原理。实际上,您正在做的是投射基本类型引用,该引用实际上指的是您刚刚确认 派生类型的对象。

settings as Settings1Manager将进行编译,因为如果演员失败,as将返回null。你和我都知道特定的演员不会失败,但编译器只是遵循它的规则。

if (typeof(Settings1Manager).IsAssignableFrom(settings.GetType()))
{
    return WriteSettings1ManagerToNetwork(settings as Settings1Manager);
}

这也有效,因为您可以向object投射任何内容,并且可以将object投射到任何内容。但是,您不希望人们在代码上看到您的名字。

return WriteSettings1ManagerToFile((Settings1Manager)(object)settings);