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

C# c中抽象类的不可空方法的可空实现#,c#,abstract,code-design,C#,Abstract,Code Design,我有三节课。实现A的名为A、B和C的接口。B也有C的实例。A的方法不能为null。但是,C可能会不时返回null。类B检查C实例的方法,如果C的返回值为null,它将返回自身值(来自B的值) 由于某些性能问题,我不想抛出异常。既然我不能将重写类的类型更改为nullable,那么我如何实现C类呢?你能强迫你的B类和C类实现一个接口来定义调用是否安全,如果不安全怎么办吗 public abstract class A { bool abstract method1(); bool a

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


由于某些性能问题,我不想抛出异常。既然我不能将重写类的类型更改为nullable,那么我如何实现C类呢?

你能强迫你的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(){
        //...
    }
}

你能强迫你的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(){
        //...
    }
}

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

据我所知,除非真正抛出异常,否则它们不会受到性能惩罚。
因此,您无法猜测在某些情况下处理异常是否更好,或者在所有情况下检查空值是否更好。

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

据我所知,除非真正抛出异常,否则它们不会受到性能惩罚。
因此,您无法猜测在某些情况下处理异常或在所有情况下检查空值是否更好。

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


如果这不是一个选项,我只会抛出一个异常并在
B
中捕获它。最好不要让
C
实现
A
,只包含获取相同数据的方法并让它们返回
bool?
。听起来,
B
仍然可以满足
A
制定的合同


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

中捕获它,按照前面所述的严格要求,我设法想出了一种愚蠢的解决方案,但哦,好吧,这是一个问题

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;
}

在严格的要求下,我设法想出了一种愚蠢的解决方案,但是,哦,好吧,这是一种东西

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;
}


请出示一些真实的代码。您的示例毫无意义,因为这两个方法都返回一个
bool
,它永远不能为
null
。这就是重点。类C从可能为null的SQL数据库中读取数据。而类B则从XMl文件中获取数据。值在数据库中存储为“true”、“false”和“default”,但它们也可以为null。在这种情况下,
C
无法实现
A
,因为它不符合约定。@beebee如果是这种情况,您需要使用
bool?
而不是
bool
(在基类中).你为什么坚持用
C
来实现
A
?这毫无意义-它不符合
A
定义的合同。不要担心代码的气味。首先要担心错误的设计决策!请出示一些真实的代码。您的示例毫无意义,因为这两个方法都返回一个
bool
,它永远不能为
null
。这就是重点。类C从可能为null的SQL数据库中读取数据。而类B则从XMl文件中获取数据。值在数据库中存储为“true”、“false”和“default”,但它们也可以为null。在这种情况下,
C
无法实现
A
,因为它不符合约定。@beebee如果是这种情况,您需要使用
bool?
而不是
bool
(在基类中).你为什么坚持用
C
来实现
A
?这毫无意义-它不符合
A
定义的合同。不要担心代码的气味。首先要担心错误的设计决策!伊萨菲并不直截了当。正如我所说,数据库记录的值可能是“默认值”。在这种情况下,它将调用B函数。所以记录可能是这样的:记录:“真”、“假”、“默认”。默认情况下,我必须调用B方法,而对于“true”和“false”,C方法正在被调用。我可以将列名传递给isSafe,但听起来仍然像是一个黑客。老实说,你的整个问题似乎有点黑客=)C.isSafe并不简单。正如我所说,数据库记录的值可能是“默认值”。在这种情况下,它将调用B函数。所以记录可能是这样的:记录:“真”、“假”、“默认”。默认情况下,我必须调用B方法,而对于“true”和“false”,C方法正在被调用。我可以将列名传递给isSafe,但听起来仍然像是一个黑客。老实说,整个问题似乎有点黑客=)谢谢Cemaphor,我将尝试讨论它。谢谢Cemaphor,我将尝试讨论它。非常感谢Aaron。我承认有更好的解决办法,我知道这一点。问题是我不能把“?”放在接口方法中。我不能,因为我没有访问它的权限。更新我的答案让它有点疯狂,但我喜欢在这样的东西上练习我的编码,所以谢谢!惊人的亚伦!非常感谢。你的编码技能真是棒极了。=)非常感谢你,亚伦。我承认有更好的解决办法,我知道这一点。问题是我不能把“?”放在界面上