C# 在a'中对所有类进行子类化;链';子类的定义

C# 在a'中对所有类进行子类化;链';子类的定义,c#,inheritance,multiple-inheritance,C#,Inheritance,Multiple Inheritance,我举了这个例子来澄清我的问题 我们从基类开始 /// <summary> /// Just a silly example class /// </summary> class CFileStream { protected readonly string FilePath; public CFileStream(string filePath) { FilePath = filePath; } public v

我举了这个例子来澄清我的问题

我们从基类开始

/// <summary>
/// Just a silly example class
/// </summary>
class CFileStream
{
    protected readonly string FilePath;

    public CFileStream(string filePath)
    {
        FilePath = filePath;
    }

    public virtual void Write(string s)
    {
        var stream = GetStream(FilePath);
        //etc
    }

    /// <summary>
    /// Take filePath as an argument to make subclassing easier
    /// </summary>
    protected virtual FileStream GetStream(string filePath)
    {
        return new FileStream(filePath, FileMode.OpenOrCreate);
    }
}
//
///只是一个愚蠢的例子
/// 
类文件流
{
受保护的只读字符串文件路径;
公共CFileStream(字符串文件路径)
{
FilePath=FilePath;
}
公共虚拟无效写入(字符串s)
{
var stream=GetStream(FilePath);
//等
}
/// 
///将filePath作为参数以简化子类化
/// 
受保护的虚拟文件流GetStream(字符串文件路径)
{
返回新的文件流(filePath,FileMode.OpenOrCreate);
}
}
为它创建一个子类

/// <summary>
/// Building on top of CFileStream, created an encrypted version
/// </summary>
class CFileStreamEncrypted : CFileStream
{
    private readonly string _key;

    public CFileStreamEncrypted(string filePath, string key):base(filePath)
    {
        _key = key;
    }

    /// <summary>
    /// For added complexity, let's also wrap a possible excepton
    /// </summary>
    public override void Write(string s)
    {
        try
        {
            base.Write(s);
        }
        catch (ImaginaryCryptoException ex)
        {
            throw new ImaginaryCustomException("bladibla", ex);
        }
    }

    /// <summary>
    /// Wrap the base stream in an imaginary crypto class
    /// </summary>
    protected override FileStream GetStream(string filePath)
    {
        return new CImaginaryCryptoStream(base.GetStream(filePath), _key);
    }
}
//
///在CFileStream的基础上创建了一个加密版本
/// 
类CFileStream加密:CFileStream
{
私有只读字符串\u密钥;
公共CFileStreamEncrypted(字符串文件路径,字符串键):基本(文件路径)
{
_钥匙=钥匙;
}
/// 
///为了增加复杂性,让我们也包装一个可能的例外
/// 
公共重写无效写入(字符串s)
{
尝试
{
base.Write(s);
}
捕获(ImaginaryCryptoException ex)
{
抛出新的ImaginaryCustomException(“bladibla”,ex);
}
}
/// 
///将基流包装在一个虚构的加密类中
/// 
受保护的覆盖文件流GetStream(字符串文件路径)
{
返回新的cimagnarycrycryptostream(base.GetStream(filePath),\u键);
}
}
现在,我们希望创建第二个子类,但它可以与初始filewriter以及加密版本一起使用

第一个是有道理的

/// <summary>
/// Building on top of CFileStream, created an auto-split version
/// </summary>
class CFileStreamSplit : CFileStream
{
    public CFileStreamSplit(string filePath) 
        : base(filePath)
    {
    }

    protected int Counter;

    /// <summary>
    /// Close stream and move to next file at the appropriate time(s)
    /// </summary>
    public override void Write(string s)
    {
        do
        {
            Stream stream;
            if (ImaginaryBooleanMustSplit)
                stream = GetStream(FilePath);
            //etc
        } while (ImaginaryBooleanDataLeftToWrite);
    }

    /// <summary>
    /// Get base stream but with altered filePath
    /// </summary>
    protected override FileStream GetStream(string filePath)
    {
        return base.GetStream(GetNextpath(filePath));
    }

    /// <summary>
    /// Ignore proper extension / file-exists etc.
    /// </summary>
    protected virtual string GetNextpath(string filePath)
    {
        return filePath + ++Counter;
    }
}
//
///在CFileStream的基础上创建了一个自动拆分版本
/// 
类CFileStreamSplit:CFileStream
{
公共CFileStreamSplit(字符串文件路径)
:base(文件路径)
{
}
受保护整数计数器;
/// 
///关闭流并在适当的时间移动到下一个文件
/// 
公共重写无效写入(字符串s)
{
做
{
溪流;
如果(想象布尔值必须拆分)
stream=GetStream(文件路径);
//等
}while(想象BooleanDataLeftToWrite);
}
/// 
///获取基流,但更改了文件路径
/// 
受保护的覆盖文件流GetStream(字符串文件路径)
{
返回base.GetStream(GetNextpath(filePath));
}
/// 
///忽略正确的扩展名/文件存在等。
/// 
受保护的虚拟字符串GetNextpath(字符串文件路径)
{
返回filePath+++计数器;
}
}
第二个(在下面)是完全重复的代码,除了构造函数,它现在也需要加密密钥

/// <summary>
/// Build the same auto-split version but this time on top of the encrypted subclass
/// </summary>
class CFileStreamSplitEncrypted : CFileStreamEncrypted
{
    public CFileStreamSplitEncrypted(string filePath, string key)
        : base(filePath, key)
    {
    }

    /*
     * Note that there are no changes below this line
     */

    protected int Counter;

    /// <summary>
    /// Close stream and move to next file at the appropriate time(s)
    /// </summary>
    public override void Write(string s)
    {
        do
        {
            Stream stream;
            if (ImaginaryBooleanMustSplit)
                stream = GetStream(FilePath);
            //etc
        } while (ImaginaryBooleanDataLeftToWrite);
    }

    /// <summary>
    /// Get base stream but with altered filePath
    /// </summary>
    protected override FileStream GetStream(string filePath)
    {
        return base.GetStream(GetNextpath(filePath));
    }

    /// <summary>
    /// Ignore proper extension / file-exists etc.
    /// </summary>
    protected virtual string GetNextpath(string filePath)
    {
        return filePath + ++Counter;
    }
}
//
///构建相同的自动拆分版本,但这次是在加密的子类之上
/// 
类CFileStreamSplitEncrypted:CFileStreamEncrypted
{
公共CFileStreamSplitEncrypted(字符串文件路径、字符串密钥)
:base(文件路径,键)
{
}
/*
*请注意,此行下没有任何更改
*/
受保护整数计数器;
/// 
///关闭流并在适当的时间移动到下一个文件
/// 
公共重写无效写入(字符串s)
{
做
{
溪流;
如果(想象布尔值必须拆分)
stream=GetStream(文件路径);
//等
}while(想象BooleanDataLeftToWrite);
}
/// 
///获取基流,但更改了文件路径
/// 
受保护的覆盖文件流GetStream(字符串文件路径)
{
返回base.GetStream(GetNextpath(filePath));
}
/// 
///忽略正确的扩展名/文件存在等。
/// 
受保护的虚拟字符串GetNextpath(字符串文件路径)
{
返回filePath+++计数器;
}
}

当然,这里有很多方法可以减少重复代码的数量,但是我还没有找到“最好”的方法,即使有这样的方法。所以根据您的意见/经验,什么是最省时、最干净、最灵活的方式来解决这个问题?

对于不同的修改,合理的方式可能是组合而不是继承。将您的类设置为只负责一件事,接受基于构造的基本流

interface ICFileStream
{
    void Write(string s);
    FileStream GetStream(string filePath);
}

/// <summary>
/// Just a silly example class
/// </summary>
class CFileStream: ICFileStream
{
    protected readonly string FilePath;

    public CFileStream(string filePath)
    {
        FilePath = filePath;
    }

    public void Write(string s)
    {
        var stream = GetStream(FilePath);
        //etc
    }

    /// <summary>
    /// Take filePath as an argument to make subclassing easier
    /// </summary>
    protected FileStream GetStream(string filePath)
    {
        return new FileStream(filePath, FileMode.OpenOrCreate);
    }
}

/// <summary>
/// Building on top of CFileStream, created an encrypted version
/// </summary>
class CFileStreamEncrypted : ICFileStream
{
    private readonly string _key;
    private readonly ICFileStream _stream;

    public CFileStreamEncrypted(string key, ICFileStream stream)
    {
        _key = key;
        _stream = stream;
    }

    /// <summary>
    /// For added complexity, let's also wrap a possible excepton
    /// </summary>
    public void Write(string s)
    {
        try
        {
            _stream.Write(s);
        }
        catch (ImaginaryCryptoException ex)
        {
            throw new ImaginaryCustomException("bladibla", ex);
        }
    }

    /// <summary>
    /// Wrap the base stream in an imaginary crypto class
    /// </summary>
    protected FileStream GetStream(string filePath)
    {
        return new CImaginaryCryptoStream(_stream.GetStream(filePath), _key);
    }
}

class CFileStreamSplit : ICFileStream
{
    private readonly ICFileStream _stream;

    public CFileStreamSplit(ICFileStream stream) 
    {
        _stream = stream;
    }

    protected int Counter;

    /// <summary>
    /// Close stream and move to next file at the appropriate time(s)
    /// </summary>
    public void Write(string s)
    {
        do
        {
            Stream stream;
            if (ImaginaryBooleanMustSplit)
                stream = GetStream(FilePath);
            //etc
        } while (ImaginaryBooleanDataLeftToWrite);
    }

    /// <summary>
    /// Get base stream but with altered filePath
    /// </summary>
    protected FileStream GetStream(string filePath)
    {
        return _stream.GetStream(GetNextpath(filePath));
    }

    /// <summary>
    /// Ignore proper extension / file-exists etc.
    /// </summary>
    protected string GetNextpath(string filePath)
    {
        return filePath + ++Counter;
    }
}

这更灵活,因此当您想添加LoggingCFileStream时,例如,您不需要为每个组合添加单独的类。

请在投票时详细说明,谢谢,我曾考虑过使用接口作为基础,因为它确实更干净,但组合而不是继承的“问题”意味着在重构现有代码时要做更多的更改,但我想这是最小化重复代码的一个折衷办法哦,顺便说一句,这样做还意味着使用受保护的方法(GetStream)这是我想避免的。。。有什么想法吗?
new  CFileStreamSplit(new CFileStreamEncrypted("crypto-awesome-key", new CFileStream("C:\\blah...")));