Pregunta

today I saw a snipped that looked really horrible to me, but unfortunetly I cannot simply change it, so I wonder if I can bypass this somehow. I have a class with a constructor that has an output-parameter for success. But that looks really ugly to me. And now when deriving from this class I have to take this param with me- if I want to or not.

class ClassA {
    ClassA(out bool success) {...}
}

class B: ClassA {
    // call the constructor from ClassA but without the out-param
}

So I´d know if its good practise or if not how I can avoid declaring the out-param from ClassB.

¿Fue útil?

Solución 3

Well, the design of that class is broken anyway, so let's break it a bit more (NOTE! I do not recommend this approach!):

void Main()
{

}

public class ClassA
{
    public ClassA(out bool success)
    {
        success = true;
    }
}

public class B: ClassA
{
    private static bool success;

    // call the constructor from ClassA but without the out-param
    public B()
        : base(out success)
    {
    }
}

Other than that, the closest you can get is making a factory method:

public class B : ClassA
{
    public static B Create()
    {
        bool success;
        var result = new B(out success);
        if (success)
            return result;
        // TODO: Dispose result?
        throw new StupidProgrammerException();
    }
}

Otros consejos

While passing ref or out parameters to a constructor is ugly, there are some types where attempts to create a usable instance will have side-effects, and might fail after some of those side-effects have already occurred. If it is not possible to construct a valid object, the only ways via which the constructor can pass information to the caller are by storing it in a threadstatic field, encapsulating it within the thrown exception, storing or feeding it to a passed-in object or delegate, or writing it to a ref/out parameter. Of those, only the ref/out parameter makes obvious the existence of information with which the client code should be doing something.

The existence of ref or out parameters is often an indication that a constructor should be protected, and that outside code should go through a factory methods which ensure that if an exception is thrown the passed-out object will get used suitably. For a class to reasonably support inheritance, however, it must offer at least one constructor which is visible outside it. Having that constructor use an out or ref parameter may be the least evil way for a class to let a caller know what things will need cleaning up if construction fails.

You can do something like this:

class ClassA
{
    protected ClassA(out bool success)
    {
        success = true;
    }
}

class B : ClassA
{
    [ThreadStatic]
    static bool success; // static to use in base(out success) call

    public bool Success
    {
        get;
        private set;
    }

    public B()
        : base(out success)
    {
        Success = success;
        success = false; // reset value
    }
}

It's ugly, but at least you get rid of the out parameter if so you want.

If you really don't care about the value of the out parameter, in newer versions of C# you can declare an out variable inline and you can choose to do nothing with it:

class B : ClassA
{
    B() : base(out bool ignore) { }
}

You can go further and use the special discard name _ to let the compiler know you won't use the variable. This way you don't even need to declare its type:

class B : ClassA
{
    B() : base(out _) { }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top