Полиморфизм и проблема литья - PullRequest
1 голос
/ 05 августа 2010

Чтобы объяснить мою проблему, вот пример

namespace CheckAbstarct
{

class Program
{
    static void Main(string[] args)
    {
        myAbstarctClass mac1 = ObjectFactory.ObjectCreator("aaa");
        myAbstarctClass mac2 = ObjectFactory.ObjectCreator("bbb");
        mac1.changeMyString();
        mac2.changeMyString();
        string myString = (string)mac2.returnMyObject();
        DateTime myObject = (DateTime) mac1.returnMyObject();

        object obj1 = mac1.returnMyObject();
        object obj2 = mac2.returnMyObject();

        myMethod(obj1);  //---> This is not compiling
        myMethod(obj2);  //---> This is not compiling

        myMethod(myString);  //---> works fine
        myMethod(myObject);  //---> works fine

        Console.ReadKey();
    }
    public static void myMethod(DateTime dt)
    {
    }
    public static void myMethod(string st)
    {
    }
}
abstract class myAbstarctClass
{
    protected string mMyString;
    public myAbstarctClass()
    {
        mMyString = "myAbstarctClass ";
    }
    public abstract void changeMyString();
    public abstract object returnMyObject();        
}

class MyNewAbstractClass1 : myAbstarctClass
{
    DateTime mObject;
    public MyNewAbstractClass1(string myString)
    {
        mMyString = myString;
        mObject = new DateTime().Date;
    }
    public override void changeMyString()
    {
        mMyString += " MyNewAbstractClass1";
        Console.WriteLine(mMyString);
    }
    public override object returnMyObject()
    {
        return mObject;
    }
}

class MyNewAbstractClass2 : myAbstarctClass
{
    string mString;
    public MyNewAbstractClass2(string myString)
    {
        mMyString = myString;
        mString = mMyString;
    }
    public override void changeMyString()
    {
        mMyString += " MyNewAbstractClass2";
        Console.WriteLine(mMyString);
    }
    public override object returnMyObject()
    {
        return mString;
    }
}

static class ObjectFactory
{
    public static myAbstarctClass ObjectCreator(string myString)
    {
        switch (myString)
        {
            case "aaa":
                return new MyNewAbstractClass1(myString);
            case "bbb":
                return new MyNewAbstractClass2(myString);
            default:
                return null;
        }
    }
}    
}

Моя проблема в том, что в Main () я не знаю, какой тип возвращает метод returnMyObject (), поэтому я не могу отправить его в MyMethod. Есть ли способ кастовать объекты ??

Ответы [ 6 ]

5 голосов
/ 05 августа 2010

Поскольку в своем дизайне returnMyObject() вы вернулись к наиболее распространенным object ссылкам, вам придется выяснить во время выполнения:

if (obj1 is string)
     myMethod((string)obj1);  //--->cast it 
else if (obj1 is DateTime)
     myMethod((DateTime) obj1);
4 голосов
/ 05 августа 2010

Вы можете проверить тип объекта во время выполнения:

public static void myMethod(Object o)
{
    if (o is DateTime)
        myMethod((DateTime)o);
    else if (o is string)
        myMethod((string)o);
}

Хотя в вашем случае вы также можете передать экземпляр myAbstarctClass в myMethod, а затем вызвать returnMyObject() там.

1 голос
/ 06 августа 2010

Используйте механизмы полиморфизма, чтобы вам не нужно было знать тип объекта.

Сделайте myMethod абстрактным методом myAbstarctClass и предоставьте реализации как MyNewAbstractClass1, так и MyNewAbstractClass2.

Изменить myAbstractClass1.returnMyObject(), чтобы вернуть myAbstarctClass (не object).

Затем можно написать код теста в Main:

...
myAbstarctClass obj1 = mac1.returnMyObject();
myAbstarctClass obj2 = mac2.returnMyObject();

obj1.myMethod();        // calls MyNewAbstractClass1.myMethod()
                        // no if statement required!

obj2.myMethod();        // calls MyNewAbstractClass2.myMethod()
                        // no if statement required!

Console.ReadKey();

Редактировать: Это можно еще более упростить, поскольку методы returnMyObject() больше не нужны - они просто возвращают объект, который у вас уже есть. Тестовый код теперь просто:

mac1.myMethod();
mac2.myMethod();

// etc...
Console.ReadKey();
1 голос
/ 05 августа 2010

Вы можете использовать динамическую функцию из C # 4.0 или изменить дизайн, чтобы использовать какую-то технику двойной отправки

        dynamic obj1 = mac1.returnMyObject();
        dynamic obj2 = mac2.returnMyObject();
0 голосов
/ 08 августа 2010

Поскольку вы, кажется, используете свой класс в качестве контейнера для типа (например, DateTime, string), возможно, Generics будет лучшим выбором, чем Inheritance:

namespace CheckAbstract
{
    class Program
    {
        static void Main(string[] args)
        {
            myTemplateClass<DateTime> mac1 = new myTemplateClass<DateTime>(new DateTime().Date);
            myTemplateClass<string> mac2 = new myTemplateClass<string>("cat dog");

            mac1.changeMyString();
            mac2.changeMyString();
            string myString = (string)mac2.returnMyObject();
            DateTime myObject = (DateTime) mac1.returnMyObject();

            myMethod<string>(myString);
            myMethod<DateTime>(myObject);

            Console.ReadKey();
        }

        public static void myMethod<T>(T obj)
        {
        }
    }

    class myTemplateClass<T>
    {
        T mObject;
        string mMyString;
        public myTemplateClass(T init)
        {
            mMyString = init.ToString();
            mObject = init;
        }
        public void changeMyString()
        {
            mMyString += " " + mObject.ToString();
            Console.WriteLine(mMyString);
        }
        public T returnMyObject()
        {
            return mObject;
        }
    }
}
0 голосов
/ 05 августа 2010

Нет, вам нужно либо создать переключатель со всеми возможностями, либо что-то вроде Dictionary<Type, Delegate>

или вы можете просто сделать myMethod (объект obj)

это называется Multiple dispatch (http://en.wikipedia.org/wiki/Multiple_dispatch), и есть некоторые библиотеки, которые могут это сделать

...