Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I downcast an instance generated by static method?

Tags:

c#

I have a problem with a C# program that includes the following :

class Program
{
    static void Main(string[] args)
    {
        Child childInstance = Child.ParseFromA(@"path/to/Afile") as Child;
    }
}

class Parent{
    int property;

    public static Parent ParseFromA(string filename)
    {
        Parent parent = new Parent();
        // parse file and set property here...
        return parent;
    }
}

class Child : Parent
{
    public void SomeAdditionalFunction() { }
}

When running this code, childInstance becomes null.

I tried below assignment with explicit cast, but ended with an exception :
Child childInstance = (Child)Child.ParseFromA(@"path/to/Afile");

Since I want to parse some types of files into Parent and Child instance, I want to keep the design that generates instances by static methods.

How should I get a proper childInstance?

like image 323
Malboma99 Avatar asked Oct 28 '16 08:10

Malboma99


People also ask

Can a static method return an instance?

A static method cannot reference instance member variables directly. A static method cannot call an instance method directly.

How do you call an instance method from a static method?

Static methods can't access instance methods and instance variables directly. They must use reference to object. And static method can't use this keyword as there is no instance for 'this' to refer to.

How do you create an instance of a static class?

In C#, one is allowed to create a static class, by using static keyword. A static class can only contain static data members, static methods, and a static constructor.It is not allowed to create objects of the static class. Static classes are sealed, means you cannot inherit a static class from another class.

How an instance method is different from a static method?

Instance methods need a class instance and can access the instance through self . Class methods don't need a class instance. They can't access the instance ( self ) but they have access to the class itself via cls . Static methods don't have access to cls or self .


2 Answers

You cannot downcast it. Once an object has been created as a Parent, it will always be a Parent. It's like trying to downcast a new object() to a string: That just won't work - which character sequence should this string represent?

Thus, your only solution is to create the correct object. The only option I see in your case is to make your static method generic:

public static T ParseFromA<T>(string filename) where T : Parent, new()
{
    T t = new T();
    // parse file and set property here...
    return t;
}

Usage:

Child childInstance = Parent.ParseFromA<Child>(@"path/to/Afile");

The generic constraint T : Parent ensures that T is a subtype of Parent, and new() ensures that T has a parameterless constructor.

like image 144
Heinzi Avatar answered Oct 12 '22 12:10

Heinzi


If you insist on using static methods and do not want to use reflection or generics, then you can also consider using new keyword:

class Parent
{
    public static Parent ParseFromA(string filename)
    {
        Parent parent = new Parent();
        parent.Parse(filename);
        return parent;
    }

    protected virtual void Parse(string fileName)
    {
        ...
    }
}

class Child : Parent
{
    public new static Child ParseFromA(string filename)
    {
        Child child = new Child();
        child.Parse(filename);
        return parent;
    }

    protected override void Parse(string fileName)
    {
        base.Parse(fileName);
        SomeAdditionalFunction();
    }
}

Personally I would just use instance methods.

var child = new Child(...);
child.Parse(...);

An extra line of code is a small price to pay for cleaner code, IMHO. static keyword does not play well with inheritance, as you can see. You can also always wrap instance method into extension method, if you want a one-liner after all:

public static class ParentEx
{
    public static T ParseFile<T>(this T source, string fileName) : where T : Parent
    {
        source.Parse(fileName);
        return source;
    }
}

and then

var child = new Child().ParseFile(fileName);
like image 21
Nikita B Avatar answered Oct 12 '22 12:10

Nikita B