Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 强相关类和类型安全抽象_C# - Fatal编程技术网

C# 强相关类和类型安全抽象

C# 强相关类和类型安全抽象,c#,C#,我正在设计一个可以处理多个数据源的系统。这些数据源具有标识符,可以在创建它们时对其进行某些检查。它允许获取历史和实时数据。我当前的抽象涉及三个基类 DataSource类负责连接到服务,并维护该数据源的机密信息,包括如何打开和关闭连接以及线程安全问题 DataContext类负责获取哪些值,无论是实时值还是历史值,以及在什么日期等,在其他上下文中,您可能需要混合历史日期(参数化),这就是为什么我希望使用多态性来实现这一点 Identifier类负责解析字符串并对正则表达式进行验证,以确保传入的字

我正在设计一个可以处理多个数据源的系统。这些数据源具有标识符,可以在创建它们时对其进行某些检查。它允许获取历史和实时数据。我当前的抽象涉及三个基类

DataSource类负责连接到服务,并维护该数据源的机密信息,包括如何打开和关闭连接以及线程安全问题

DataContext类负责获取哪些值,无论是实时值还是历史值,以及在什么日期等,在其他上下文中,您可能需要混合历史日期(参数化),这就是为什么我希望使用多态性来实现这一点

Identifier类负责解析字符串并对正则表达式进行验证,以确保传入的字符串标识符至少在某种程度上是有效的。它还用于类型安全,因为不允许将一个数据源的标识符传递到另一个数据源

参见下面的示例代码

public class DataSource
{
    // base class for all data sources
    // maintains connections opening and closing plus 
    // thread safety concerns
}
public class FooDataSource : DataSource { }

public class BarDataSource : DataSource { }

public abstract class Identifier
{
    public string Value { get; internal set; }

    public Identifier(string value)
    {
        Value = value; 
    }
}

public class FooIdentifier : Identifier
{
    public FooIdentifier(string value) : base(value)
    {
        // checks go here on the string that comes in 
        // specific to the foo data source
    }
}

public class BarIdentifier : Identifier
{
    public BarIdentifier(string value) : base(value)
    {
        // checks on the string values that come in for the Bar 
        // source 
    }
}


public abstract class DataContext<TIdentifier> where TIdentifier : Identifier
{
    public abstract double GetValue(TIdentifier id); 
}

public abstract class FooDataContext : DataContext<FooIdentifier> { }

public abstract class BarDataContext : DataContext<BarIdentifier> { }

public class FooRealTimeDataContext : FooDataContext
{
    public override double GetValue(FooIdentifier id)
    {
        // real implementation here 
        return -1; 
    }
}

public class BarRealTimeDataContext : BarDataContext
{
    public override double GetValue(BarIdentifier id)
    {
        // real implementation here
        return -10; 
    }
}


[TestFixture]
public static class TestMe
{
    [Test]
    public static void MyTest()
    {
        // create the data context (to get data from) 
        var ctx = new FooRealTimeDataContext();

        ctx.GetValue(new FooIdentifier("onetuhoenthuo")); // compiles (good)
        // ctx.GetValue(new BarIdentifier("noetuhneoth")); // does not compile (also good)
    }
}
公共类数据源
{
//所有数据源的基类
//保持连接打开和关闭
//线程安全问题
}
公共类FoodDataSource:DataSource{}
公共类BarDataSource:数据源{}
公共抽象类标识符
{
公共字符串值{get;内部集;}
公共标识符(字符串值)
{
价值=价值;
}
}
公共类标识符:标识符
{
公共标识符(字符串值):基(值)
{
//在输入的字符串上进行检查
//特定于foo数据源
}
}
公共类标识符:标识符
{
公共BarIdentifier(字符串值):基(值)
{
//检查为条输入的字符串值
//来源
}
}
公共抽象类DataContext,其中TIdentifier:标识符
{
公共摘要双GetValue(TIdentifier id);
}
公共抽象类FooDataContext:DataContext{}
公共抽象类BarDataContext:DataContext{}
公共类FooRealTimeDataContext:FooDataContext
{
公共覆盖双GetValue(FooIdentifier id)
{
//这里真正的实施
返回-1;
}
}
公共类BarRealTimeDataContext:BarDataContext
{
公共覆盖双GetValue(BarIdentifier id)
{
//这里真正的实施
返回-10;
}
}
[测试夹具]
公共静态类TestMe
{
[测试]
公共静态void MyTest()
{
//创建数据上下文(从中获取数据)
var ctx=新的FooRealTimeDataContext();
ctx.GetValue(新的FooIdentifier(“onetuhoenthuo”);//编译(良好)
//ctx.GetValue(新的BarIdentifier(“noetuhneoth”);//无法编译(也很好)
}
}
问题(最后)是如何创建一个实际遵循OOP原则的类来填充下面的类外壳

public class UniversalRealTimeDataSource : DataSource<Identifier> {
    public double GetValue(Identifier id) {
        // there would have to be code in here that says "if(id is FooIdentifier) ... else ... 
        // which is (IMO) an anti-pattern so, how to avoid this? 
    }
}
公共类UniversalRealTimeDataSource:DataSource{ 公共双GetValue(标识符id){ //这里必须有一段代码,上面写着“如果(id是foodidentifier)…否则。。。 //哪一种(IMO)是反模式?那么,如何避免这种情况? } }
编辑:我一直在尽可能地保持编译时类型的安全保证。如果(!(id是foodidentifier))有一些
,这将是相当简单的
抛出异常类型的代码,但我想使其不可能在编译时发生。

我的最终解决方案在编译时类型安全性方面有点折衷。标识符从数据源菜单中选择自己的数据源(通用数据源)。这可以防止运行时错误,除非程序员错误地使用代码。许多内容可能会被设置为私有,公共层将包括所有DataContext和Identifier子类

public abstract class DataSource
{
    // base class for all data sources
    // maintains connections opening and closing plus 
    // thread safety concerns

    // these classes will most likely be private
    // maybe even within the universal data source class as inner classes

    // THE TWO METHODS BELOW ARE ONLY TO BE CALLED FROM WITHIN THE UniversalDataSource CLASS
    public abstract double GetRealTimeValue(Identifier id);

    public abstract double GetHistoricalValue(Identifier id, DateTime asof); 
}
public class FooDataSource : DataSource {
    public override double GetRealTimeValue(Identifier id)
    {
        return -1;
        // real implementation here, must be identifier type upcasting with runtime check
    }

    public override double GetHistoricalValue(Identifier id, DateTime asof)
    {
        return -2; 
        // real implementation here, must be identifier type upcasting with runtime check
    }
}

public class BarDataSource : DataSource {
    public override double GetRealTimeValue(Identifier id)
    {
        return -3; 
        // real implementation here, must be identifier type upcasting with runtime check
    }

    public override double GetHistoricalValue(Identifier id, DateTime asof)
    {
        return -4; 
        // real implementation here, must be identifier type upcasting with runtime check
    }
}

/// <summary>
/// holds initialized references to all possible data sources
/// </summary>
public class UniversalDataSource 
{

    public FooDataSource FooDS { get; internal set; }
    public BarDataSource BarDS { get; internal set; }

    public UniversalDataSource(FooDataSource fooDs, BarDataSource barDs)
    {
        this.FooDS = fooDs;
        this.BarDS = barDs;
    }

    public double GetRealTimeValue(Identifier id)
    {
        var specificDS = id.GetDataSource(this);
        return specificDS.GetRealTimeValue(id); 
    }

    public double GetHistoricalValue(Identifier id, DateTime asof)
    {
        var specificDS = id.GetDataSource(this);
        return specificDS.GetHistoricalValue(id, asof); 
    }
}

public abstract class Identifier
{
    public string Value { get; internal set; }

    public Identifier(string value)
    {
        Value = value; 
    }

    /// <summary>
    /// returns the appropriate data source for THIS kind of identifier (abstractly)
    /// </summary>
    /// <param name="universalDataSource"></param>
    /// <returns></returns>
    public abstract DataSource GetDataSource(UniversalDataSource universalDataSource); 
}

public class FooIdentifier : Identifier
{
    public FooIdentifier(string value) : base(value)
    {
        // checks go here on the string that comes in 
        // specific to the foo data source
    }

    public override DataSource GetDataSource(UniversalDataSource universalDataSource)
    {
        return universalDataSource.FooDS; 
    }
}

public class BarIdentifier : Identifier
{
    public BarIdentifier(string value) : base(value)
    {
        // checks on the string values that come in for the Bar 
        // source 
    }

    public override DataSource GetDataSource(UniversalDataSource universalDataSource)
    {
        return universalDataSource.BarDS; 
    }
}


public abstract class DataContext
{
    public UniversalDataSource DataSource { get; internal set; }

    protected DataContext(UniversalDataSource dataSource)
    {
        DataSource = dataSource;
    }

    public abstract double GetValue(Identifier id); 
}

public class RealTimeDataContext : DataContext {

    public RealTimeDataContext(UniversalDataSource dataSource) : base(dataSource)
    {
    }

    public override double GetValue(Identifier id)
    {
        return DataSource.GetRealTimeValue(id); 
    }
}

public class HistoricalDataContext : DataContext {

    public DateTime AsOf { get; internal set; }

    public HistoricalDataContext(UniversalDataSource dataSource, DateTime asof) : base(dataSource)
    {
        AsOf = asof; 
    }

    public override double GetValue(Identifier id)
    {
        return DataSource.GetHistoricalValue(id, AsOf); 
    }

}

[TestFixture]
public static class TestMe
{
    [Test]
    public static void MyTest()
    {
        // create the data context (to get data from) 
        var ds = new UniversalDataSource(
            new FooDataSource(),
            new BarDataSource()
            );

        var realTimeDataContext = new RealTimeDataContext(ds);
        var historicalDataContext = new HistoricalDataContext(ds, DateTime.MinValue);

        var fooId = new FooIdentifier("onetuhoenthuo");
        var barId = new BarIdentifier("onetuhoenthuo"); 

        // testing dispatch
        Assert.AreEqual(-1, realTimeDataContext.GetValue(fooId));
        Assert.AreEqual(-2, historicalDataContext.GetValue(fooId));
        Assert.AreEqual(-3, realTimeDataContext.GetValue(barId));
        Assert.AreEqual(-4, historicalDataContext.GetValue(barId)); 

    }
}
公共抽象类数据源
{
//所有数据源的基类
//保持连接打开和关闭
//线程安全问题
//这些课程很可能是私人的
//甚至可能在通用数据源类中作为内部类
//下面的两个方法只能从UniversalDataSource类中调用
公共抽象双GetRealTimeValue(标识符id);
公共抽象双GetHistoricalValue(标识符id、日期时间asof);
}
公共类FoodDataSource:DataSource{
公共重写双GetRealTimeValue(标识符id)
{
返回-1;
//这里的实际实现必须是标识符类型的向上转换和运行时检查
}
公共重写双GetHistoricalValue(标识符id、日期时间asof)
{
返回-2;
//这里的实际实现必须是标识符类型的向上转换和运行时检查
}
}
公共类BarDataSource:数据源{
公共重写双GetRealTimeValue(标识符id)
{
返回-3;
//这里的实际实现必须是标识符类型的向上转换和运行时检查
}
公共重写双GetHistoricalValue(标识符id、日期时间asof)
{
返回-4;
//这里的实际实现必须是标识符类型的向上转换和运行时检查
}
}
/// 
///保存对所有可能数据源的初始化引用
/// 
公共类通用数据源
{
公共FoodDataSource FooDS{get;internal set;}
公共BarDataSource BARD{get;内部集合;}
公共通用数据源(FoodDataSource fooDs,BarDataSource barDs)
{
这就是食物;
这个。吟游诗人=吟游诗人;
}
公共双GetRealTimeValue(标识符id)
{
var specificDS=id.GetDataSource(此);
返回specificDS.GetRealTimeValue(id);
}
公共双GetHistoricalValue(标识