用于存储变量内容的通用类

时间:2017-05-12 19:33:09

标签: c# generics

我想创建一个结构来存储使用followind规范从Web服务中消耗的数据:

回应:

  • 字段1 - 指令类型:可以是1(PreferredDay),2(SVP),3(邻居)
  • 字段2:一些可变数据。它的类型取决于字段1.所以如果:

  • 字段1 == 1然后字段2类型将是DateTime(dd.MM.yyyy)

  • 字段1 == 2然后字段2类型将是字符串类型。
  • 字段1 == 3然后字段2类型将是字符串

所以,我开始使用以下枚举:

public enum InstructionType
{
    None = 0,
    PreferredDay = 1,
    ServicePoint = 2,
    Neighbour = 3
}

通用类:

public abstract class Instruction<T>
{
    public InstructionType Type { get; private set; }
    public T Data { get; private set; }

    public Instruction(InstructionType type, T data)
    {
        this.Type = type;
        this.Data = data;
    }

}

和具体课程:

 public class PreferredDayInstruction : Instruction<DateTime>
{
    public PreferredDayInstruction(DateTime data) 
        : base (InstructionType.PreferredDay, data) {}
}

    public class ServicePointInstruction: Instruction<string>
{
    public ServicePointInstruction(string data) 
        : base (InstructionType.ServicePoint, data) {}
}

    public class NeughbourInstruction: Instruction<string>
{
    public NeughbourInstruction(string data) 
        : base (InstructionType.Neighbour, data) {}
}

解析Web服务时,响应创建了一个公共函数:

     public Instruction DeliveryInstruction() <---Compiler error here "Instruction"
    {
        if (resultFromWebservice.Field1 == 1)
           return new PreferredDayInstruction((DateTime)Field2);
        if (resultFromWebservice.Field1 == 2)
           return new ServicePointInstruction(Field2);  
        if (resultFromWebservice.Field1 == 3)
           return new NeighbourInstruction(Field2);  

    }

这就是问题所在。无法返回泛型类型的对象。

尝试使用Interface,工厂和其他东西,但总是遇到同样的问题。那么,有什么办法可以实现这一目标吗?也许这是不可能的,也许是如此容易,我现在无法看到。提前谢谢。

更新 BOLD 指令的编译器错误 错误1使用泛型类型&#39; NAMESPACE.Instruction&#39;需要&#39; 1&#39;类型参数

我忘了..我正在使用.NET 3.5

2 个答案:

答案 0 :(得分:1)

看起来您可能会开始尝试使用泛型而不是使用它们,因为您已经确定了需求。经常(并非总是),当它变得困难时,因为它实际上并不适合你想要做的事情。

在这种情况下看起来很奇怪的是,您既有通用类型又有enum来表示类型。这可能会给你带来一些问题。

首先,您似乎正在尝试创建一个适合所有类的一类来模拟不同类型的行为。这将引起混乱并变得更加混乱。想想大多数属于.NET框架的类,并想象如果它们具有Field1Field2等属性会发生什么,而你无法从它们看到它们的用途。在一种方法中,它们用于一件事,但在另一种情况下,它们意味着其他东西。

另外,如果你试图在一个类中添加不同类型的指令,这表明你可能会尝试将它们全部传递给一个方法,并且该方法可以确定要做什么,也许可以调用其他方法。方法。 (我猜这是因为enum。也许你会根据它包含的值来区别地处理输入。)这种方法很难维护。

我建议您等到泛型,直到您确定需要它们为止。如果您有不同类型的指令,那么最好为每个指令编写一个不同的类,其中包含所需的属性和描述它们的名称,并为每个类编写方法以执行他们需要执行的操作。如果你需要很多课程,那就做很多。

很容易陷入尝试解决不存在的问题的陷阱,比如如何编写一个涵盖一系列不同需求的类。答案通常是你不需要的。通过编写更多每个更少事物的类,您将获得更好的结果。

答案 1 :(得分:0)

相信我,我尽力解释我的问题是什么以及我需要解决的问题。简而言之,问题很简单。这可能吗?那么,有没有办法为这3个类返回一个通用类型?答案是否定的,因为他们不共享任何根。它们都源于指令,但彼此不相容。这是我从这次经历中学到的东西。

作为另一个例子,让我们采用另一种.NET框架的通用类型。

public class ListOfString : List<string> { }

public class ListOfInt : List<int> { }

public class ListOfDecimal : List<decimal> { }

并且,在应用程序的另一个位置,获取一个基于某些逻辑返回此List之一的方法:

public class Logic
{
    public List<> GetList(Type t) <----This can't be done
    {

        if (t == typeof(string))
            return new ListOfString();
        if (t == typeof(int))
            return new ListOfInt();
        if (t == typeof(decimal))
            return new ListOfDecimal();
        else return null;
    }

}

请记住,这只是一个愚蠢的样本,只是为了说明这篇文章的重点。

顺便说一下,在List的情况下,可以完成以下操作,因为IList有一个非通用的不同版本:

public IList GetList(Type t) 
{
      ....
}

但在我的特定情况下,我无法想出一种方法。

无论如何,我终于采用了另一种方法。我重申了我真正想要的是确保Data属性有效。如果它应该是那里的日期,请确保日期有效。它是一个字符串,确保它具有正确的长度或必须遵循的任何规则。

所以这是最终解决方案:

枚举:

public enum InstructionType
{
    None = 0,
    PreferredDay = 1,
    ServicePoint = 2,
    Neighbour = 3
}

基类:

 public abstract class Instruction
{
    public InstructionType Type { get; private set; }
    public string Data { get; private set; } <---Type String

    public Instruction(InstructionType type, string data)
    {
        this.Type = type;
        this.Data = IsValid(data) ? data : string.Empty;
    }

    public abstract bool IsValid(string data); <--the rule.
}

具体课程:

public class PreferredDayInstruction : Instruction
{
    public PreferredDayInstruction(string date)
        : base(InstructionType.PreferredDay, date) { }

    public override bool IsValid(string data)
    {
        string[] formats = {"dd.MM.yyyy", "d.MM.yyyy",
                            "dd.MM.yy", "d.MM.yy"};
        try
        {
            data = data.Replace('/', '.').Replace('-', '.');
            var dateparts = data.Split('.');
            DateTime date = new DateTime(Convert.ToInt32(dateparts[2]),
                                         Convert.ToInt32(dateparts[1]),
                                         Convert.ToInt32(dateparts[0]));

            //DateTime.ParseExact(data, formats, null, System.Globalization.DateTimeStyles.AssumeLocal);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }
}


    public class ServicePointInstruction : Instruction
{
    public ServicePointInstruction(string data)
        : base (InstructionType.ServicePoint, data) { }

    public override bool IsValid(string data)
    {
        return ServicePointBarcodeValidator.Validate(data); 
    }
}

    public class NeighbourInstruction : Instruction
{
    public NeighbourInstruction(string data) :
        base(InstructionType.Neighbour, data) { }

    public override bool IsValid(string data)
    {
        return data.Length <= 70;
    }
}

工厂类,他的责任是根据枚举创建和返回正确的对象:

    public static class DeliveryInstructionFactory
{

    public static Instruction Create(int type, string data)
    {
        return Create((InstructionType)type, data);
    }

    public static Instruction Create(InstructionType type, string data)
    {
        switch (type)
        {
            case InstructionType.PreferredDay:
                return new PreferredDayInstruction(data);
            case InstructionType.ServicePoint:
                return new ServicePointInstruction(data);
            case InstructionType.Neighbour:
                return new NeighbourInstruction(data);
            default:
                return null;
        }

    }
}

最后,由于现在他们共享相同的根,因此可以在webservice的响应解析器上创建对象:

    public Instruction DeliveryInstruction()
    {
        try
        {
            int instructionCode = int.Parse(observation.Substring(173,2));
            string instructionData = observation.Substring(175, 10);

            return DeliveryInstructionFactory.Create(instructionCode, instructionData);            }
        catch (Exception ex)
        {
            Log.Error("[ValidationBarcodeResponse] DeliveryInstructions aren't in the correct format", ex);
            return null;
        }
    }

希望现在适合Minimal, Complete, and Verifiable example