我想创建一个结构来存储使用followind规范从Web服务中消耗的数据:
回应:
字段2:一些可变数据。它的类型取决于字段1.所以如果:
字段1 == 1然后字段2类型将是DateTime(dd.MM.yyyy)
所以,我开始使用以下枚举:
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
答案 0 :(得分:1)
看起来您可能会开始尝试使用泛型而不是使用它们,因为您已经确定了需求。经常(并非总是),当它变得困难时,因为它实际上并不适合你想要做的事情。
在这种情况下看起来很奇怪的是,您既有通用类型又有enum
来表示类型。这可能会给你带来一些问题。
首先,您似乎正在尝试创建一个适合所有类的一类来模拟不同类型的行为。这将引起混乱并变得更加混乱。想想大多数属于.NET框架的类,并想象如果它们具有Field1
和Field2
等属性会发生什么,而你无法从它们看到它们的用途。在一种方法中,它们用于一件事,但在另一种情况下,它们意味着其他东西。
另外,如果你试图在一个类中添加不同类型的指令,这表明你可能会尝试将它们全部传递给一个方法,并且该方法可以确定要做什么,也许可以调用其他方法。方法。 (我猜这是因为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;
}
}