【问题标题】:nullable implemention of non-nullable methods of an abstract class in c#c#中抽象类的非可空方法的可空实现
【发布时间】:2013-07-16 20:27:51
【问题描述】:

我有三门课。一个名为 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 类?

【问题讨论】:

  • 请展示一些真实的代码。你的例子没有意义,因为这两种方法都返回一个bool,它永远不可能是null
  • 这就是重点。 C 类从可能为空的 SQL 数据库中读取数据。而 B 类从 XMl 文件中获取数据。值在数据库中存储为“true”、“false”和“default”,但它们也可以为 null。
  • 在那种情况下C根本无法实现A,因为它不符合约定。
  • @beebee 如果是这种情况,您需要使用bool? 而不是bool(在基类中)。
  • 为什么坚持C实现A?这没有任何意义——它不符合A 定义的合同。不用担心代码异味。首先担心错误的设计决策!

标签: c# abstract code-design


【解决方案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

【讨论】:

  • 非常感谢亚伦。我承认有更好的解决方案,我知道这一点。问题是我不能把那个“?”在接口方法中。我不能,因为我无权访问它。
  • 更新了我的答案,让它有点疯狂,但我喜欢在这样的东西上练习我的编码,所以谢谢!
  • 惊人的亚伦!谢谢你。你的编码技巧真的很棒。 =)
【解决方案2】:

您能否强制您的 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(){
        //...
    }
}

【讨论】:

  • C.IsSafe 并不简单。正如我所说,数据库记录的值可能是“默认值”。在这种情况下,它将调用 B 函数。所以记录可能是这样的:记录:“真”,“假”,“默认”。默认情况下,我必须调用 B 方法,而对于“true”和“false”,调用 C 方法
  • 我可以将列名传递给 isSafe,但听起来仍然像 hack
  • 说实话,你的整个问题似乎有点老套 =)
【解决方案3】:

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

据我所知,异常没有性能损失,直到它们真正被抛出。 所以你无法猜测在某些情况下处理异常或在所有情况下检查空值是否更好。

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • 谢谢Cemaphor,我会努力讨论的。
    猜你喜欢
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多