c#中抽象类的非可空方法的可空实现

时间:2013-07-16 20:27:51

标签: c# abstract code-design

我有三节课。一个名为A的接口,以及实现A的B和C.另外B有一个C的实例.A的方法不能为空。但是,C可能会不时返回null。 B类检查C实例的方法,如果C的返回值为null,它将返回自身值(来自B的值)。

public abstract class A
{
bool abstract method1();
bool abstract method2();
}

public class B:A
{
public C c;
override bool method1()
{
//if c.method1 is not null return c.method1() otherwise do some other functionality
}
}

public class C:A
{
?
}

由于某些性能问题,我不想抛出异常。我怎样才能实现C类,因为我无法将覆盖类的类型更改为可为空?

4 个答案:

答案 0 :(得分:1)

您是否可以强制您的B和C类实现一个界面来定义调用是否安全以及如果不安全该怎么办?

public abstract class A
{
    bool abstract method1();
    bool abstract method2();
}

public interface IFallbackIfNotSafe {
    public bool IsSafe();
    public bool Fallback();
}

public class B : A, IFallbackIfNotSafe
{
    public C c {get;set;}

    bool override method1()
    {
        return c.IsSafe() ? c.method1() : Fallback();
    }

    bool override method2()
    {
        //...
    }

    public bool Fallback(){
        //...
    }

    public bool IsSafe(){
        // make sure this B instance is safe
    }
}

public class C : A, IFallbackIfNotSafe
{
    bool override method1()
    {
        //...
    }

    bool override method2()
    {
        //...
    }

    public bool IsSafe(){
        // make sure this C instance is safe
    }

    public bool Fallback(){
        //...
    }
}

答案 1 :(得分:1)

我只是同意其他评论员: 您已经定义了一个接口,该接口定义了您可以从实现此接口的类中获得的结果。 你不想改变hevaviour,这意味着你要么调整你的界面以满足新的要求,要么在你的C类需要违反界面定义时抛出异常(null不在def - >违规范围内)。

异常没有性能损失,因为我知道它们确实被抛出。 所以你无法猜测在某些情况下是否更好地处理异常或在所有情况下检查空值。

答案 2 :(得分:1)

最好不要C实现A,只需包含获取相同数据并让它们返回bool?的方法。听起来B仍然可以满足A所规定的合同。

如果这不是一个选项,我只会抛出一个异常并在B中捕获它。

答案 3 :(得分:1)

根据所述的严格要求,我设法提出了一种愚蠢的解决方案,但是很好 - 这是......

void Main()
{
    var a = new AProxy(new C(), new B());
    for (int i = 0; i < 15; i++)
    {
        a.method1();
        a.method2();
    }
}
public abstract class A
{
    public abstract bool method1();
    public abstract bool method2();
}
public class AProxy : A
{
    readonly A primary;
    readonly A secondary;
    public AProxy(A primary, A secondary)
    {
        this.primary = primary;
        this.secondary = secondary; 
        if(primary is IReturnsNulls)
            ((IReturnsNulls)primary).LastResultNull += (s, e) =>
                useSecondary = true;
    }
    private bool useSecondary;
    private bool UseSecondary
    {
        get 
        {
            if(useSecondary == true)
            {
                useSecondary = false;
                return true;
            }
            return useSecondary;
        }
    }
    public override bool method1()
    {
        var result = primary.method1();
        return UseSecondary ? secondary.method1() : result;
    }
    public override bool method2()
    {
        var result = primary.method2();
        return UseSecondary ? secondary.method2() : result;
    }
}
public class B : A
{
    public override bool method1()
    {
        Console.WriteLine ("B, method1 (secondary)");
        return true;
    }
    public override bool method2()
    {
        Console.WriteLine ("B, method2 (secondary)");
        return true;
    }
}
public interface IReturnsNulls
{
    event EventHandler LastResultNull;
}
public class C : A, IReturnsNulls
{   
    static Random random = new Random();
    public override bool method1()
    {
        Console.WriteLine ("C, method1");
        var result = (random.Next(5) == 1) ? (bool?)null : true;
        if(result == null && LastResultNull != null)
            LastResultNull(this, EventArgs.Empty);
        return result ?? false;
    }
    public override bool method2()
    {
        Console.WriteLine ("C, method2");
        var result = (random.Next(5) == 1) ? (bool?)null : true;
        if(result == null && LastResultNull != null)
            LastResultNull(this, EventArgs.Empty);
        return result ?? false;
    }
    public event EventHandler LastResultNull;
}

<强>输出

C, method1
B, method1 (secondary)
C, method2
C, method1
C, method2
B, method2 (secondary)
C, method1
C, method2
C, method1
C, method2
C, method1
C, method2
C, method1
C, method2
C, method1
C, method2
C, method1
C, method2
C, method1
B, method1 (secondary)
C, method2
C, method1
C, method2
C, method1
C, method2
B, method2 (secondary)
C, method1
C, method2
C, method1
C, method2
B, method2 (secondary)
C, method1
C, method2
C, method1
C, method2