C# 用于存储变量内容的泛型类

C# 用于存储变量内容的泛型类,c#,generics,C#,Generics,我想创建一个结构来存储从Web服务使用的数据,其规格如下: 答复: 字段1-指令类型:可以是1(首选日期)、2(高级副总裁)、3(邻居) 字段2:一些变量数据。其类型取决于字段1。因此,如果: 字段1==1,则字段2的类型将为DateTime(dd.MM.yyyy) 字段1==2,则字段2的类型将为字符串类型 字段1==3,则字段2的类型将为字符串类型 因此,我开始使用以下枚举: public enum InstructionType { None = 0, Preferre

我想创建一个结构来存储从Web服务使用的数据,其规格如下:

答复:

  • 字段1-指令类型:可以是1(首选日期)、2(高级副总裁)、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;
    }

}
公共抽象类指令
{
公共指令类型{get;private set;}
公共T数据{get;私有集;}
公共指令(指令类型,T数据)
{
this.Type=Type;
这个。数据=数据;
}
}
和混凝土等级:

 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) {}
}
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;
    }
}
公共类PreferredDayInstruction:指令
{
公共PreferredDay指令(日期时间数据)
:base(InstructionType.PreferredDay,数据){}
}
公共类ServicePointInstruction:指令
{
公共服务点指令(字符串数据)
:base(InstructionType.ServicePoint,数据){}
}
公共课纽堡教学:教学
{
公共Neughbour指令(字符串数据)
:base(InstructionType.nexter,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);  

    }

public-Instruction DeliveryInstruction()。通常(并非总是)当这变得困难时,是因为它实际上不符合你想要做的

在这种情况下,奇怪的是,您有一个泛型类型和一个
enum
来指示该类型。这可能会给您带来一些问题


首先,看起来您试图创建一个一刀切的类来模拟不同类型的行为。这会让人一开始就感到困惑,然后变得更加困惑。想想大多数属于.NET framework的类,想象一下如果它们有
Field1
Field2
这样的属性,并且你看不出它们的用途,会发生什么。在一种方法中,它们被用于一件事,但在另一种情况下,它们意味着另一件事

另外,如果你试图把不同类型的指令放在一个类中,这意味着你可能要尝试将它们全部传递给一个方法,这个方法会知道该做什么,并且可能会调用其他方法。(我猜是因为
enum
。也许您将根据输入包含的值来处理不同的输入。)一个方法将很难维护

我建议您等到确定需要时再使用泛型药物。如果您有不同类型的指令,您可能最好为每个指令编写一个不同的类,其中包含它需要的属性和描述它们的名称,并为每个指令编写方法来完成它们需要做的事情。如果你需要很多课程,就多上


很容易陷入试图解决不存在的问题的陷阱,比如我如何编写一个涵盖一系列不同需求的类。答案通常是你不需要。写更多的课,每个课做的事情更少,你会得到更好的结果。

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

作为另一个示例,让我们以另一个.NET framework的泛型类型为例

public class ListOfString : List<string> { }

public class ListOfInt : List<int> { }

public class ListOfDecimal : List<decimal> { }
但在我的特殊情况下,我想不出一个办法来做到这一点

不管怎样,我最终还是采用了另一种方法。我意识到我真正想要的是确保数据属性是有效的。如果它应该是一个日期在那里,确保日期是有效的。如果它是字符串,请确保它具有正确的长度或它必须遵循的任何规则

这就是最终的解决方案:

枚举:

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.
}
最后,由于它们都共享同一根,所以可以在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;
        }
    }

希望这适用于

无法返回泛型类型的对象的编译器错误。更新后如果方法总是返回
PreferredDayInstruction()
对象,那么声明返回值
Instruction
有什么意义(即使假设这是合法语法,但事实并非如此)?现在还不清楚你到底想达到什么目的。泛型
指令
类型没有根本的错误,但是您使用它的方式显然不起作用,并且您没有向任何人提供足够的上下文来帮助您理解如何正确使用它。@PeterDuniho DeliveryInstruction function edited。它不应该总是返回PreferredDayInstruction,而是从该指令派生的对象。可以是首选的DayInstruction、ServicePointInstruction或NeighbourInstruction。也许在将来,可能是一个ThrowToTheRiverIntruction(int riverId),例如。请解释调用方应该如何处理这个场景。您有一个方法可以返回
指令
指令
。在编译时,需要知道返回类型。你对呼叫中心有什么计划?你的问题仍然缺乏一个很好的例子来说明这一切。可能的解决方案包括将该方法拆分为两个非泛型方法,或者创建该方法可以返回的非泛型基类。但仍然无法确定在你的情况下什么是有效的。我确定了一个需求,因为我看到了
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;
        }

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