我有一个我正在工作的项目,它将涉及创建一个将在多个其他站点中使用的DLL。在这个DLL中,我们需要引用大约10个枚举。但是,对于使用DLL的每个站点,这些枚举的值将不同。例如:
MyBase.dll可能有一个MyClass类,其属性类型为MyEnum。
然后在MySite中引用MyBase.dll。 MyStie还会引用MyEnums.dll,它将包含MyEnum类型的值。
有没有办法实现这个目标?在构建MyBase.dll时,我知道MyEnums.dll中存在哪些枚举。问题是我无法在没有专门引用MyEnums.dll的情况下构建MyBase.dll,MyEnums.dll只有在特定项目中使用MyBase.dll才会创建。
我希望这是有道理的,希望我能在这里找到答案。
感谢。
编辑:
感谢所有评论。这需要一些阅读才能完全理解,但让我试着给出一个更好的例子来说明我在这里看到的内容。
让我们说下面的代码在我的DLL中,将被放入各种项目中。状态是一个枚举。
public Class MyClass
{
private Status _currentStatus;
public Status CurrentStatus
{
get
{
return _currentStatus;
}
}
public void ChangeStatus(Status newStatus)
{
_currentStatus = newStatus;
}
}
我希望能够在各个项目中定义Status的可能值。所以在这个DLL中,我永远不会引用Status enum中的值,我只需要知道它存在。
我希望我能做的更清楚。
答案 0 :(得分:2)
如果您希望每个客户端看到不同的枚举值(在不同的汇编版本中),那么使用枚举是一个糟糕的解决方案 - 更改将破坏客户端代码......
使用枚举可能工作(只要枚举名称和程序集名称相同且程序集未签名) - 您只需交换程序集即可。但是,如果在代码中任何位置使用的值都不在最后,那么最终会出现异常。此外,您可以明确地对值进行编号,以确保值的不同子集不会以不同值的相同数字或相同值的不同数字结束。
而是考虑使用动态构建的集合,例如列表,字典或数据库表。 或者只是向每个人提供具有相同的枚举值超集的相同程序集,并让用户决定哪些值与它们相关(可能使用值的重要前缀作为约定)。
或者你可以使用两者的组合......
生成不同的结构(不同的类型名称(或名称空间)和程序集名称)每个站点具有不同的属性(根据站点的配置文件)和一个主结构接受结构的服务。让所有结构实现相同的接口,您期望接收...
public interface IStatus
{
string GetKey();
}
public struct ClientXStatus : IStatus
{
private readonly string _key;
private ClientXStatus(string key)
{
_key = key;
}
// Don't forget default for structs is 0,
// therefore all structs should have a "0" property.
public ClientXStatus Default
{
get
{
return new ClientXStatus();
}
}
public ClientXStatus OptionB
{
get
{
return new ClientXStatus(10);
}
}
string IStatus.GetKey()
{
return _key;
}
public override bool Equals(object obj)
{
return (obj is IStatus) && ((IStatus)obj).GetKey() == _key;
}
public override int GetHashCode()
{
return _key.GetHashCode();
}
public static bool operator==(ClientXStatus x, IStatus y)
{
return x.Equals(y);
}
public static bool operator==(IStatus x, ClientXStatus y)
{
return y.Equals(x);
}
public static bool operator!=(ClientXStatus x, IStatus y)
{
return !x.Equals(y);
}
public static bool operator!=(IStatus x, ClientXStatus y)
{
return !y.Equals(x);
}
// Override Equals(), GetHashCode() and operators ==, !=
// So clients can compare structures to each other (to interface)
}
为服务使用主结构:
public struct MasterStatus : IStatus
{
private readonly string _key;
private MasterStatus(string key)
{
_key = key;
}
// Don't forget default for structs is 0,
// therefore all structs should have a "0" property.
public MasterStatus Default
{
get
{
return new MasterStatus();
}
}
// You should have all the options here
public MasterStatus OptionB
{
get
{
return new MasterStatus(10);
}
}
// Here use implicit interface implementation instead of explicit implementation
public string GetKey()
{
return _key;
}
public static implicit operator MasterStatus(IStatus value)
{
return new MasterStatus(value.GetKey());
}
public static implicit operator string(MasterStatus value)
{
return new value._key;
}
// Don't forget to implement Equals, GetHashCode,
// == and != like in the client structures
}
演示服务代码:
public void ServiceMethod(IStatus status)
{
switch (status.GetKey())
{
case (string)MasterStructA.OptionB:
DoSomething();
}
}
或者:
public void ChangeStatus(IStatus status)
{
_status = (MasterStatus)status;
}
这样你:
使用代码生成来防止值冲突。
强制用户通过隐藏值(作为私有)并仅接受您的结构来使用编译时检查(无int值或字符串值)。
在服务代码(接口)中使用真正的多态,而不是容易出错的黑客。
使用不可变值类型(如枚举)而不是引用类型。
答案 1 :(得分:0)
首先,您必须决定放置常量的WHERE。然后,您可以将enum
转换为静态属性。
例如:
public enum MyEnum
{
Value1,
Value2
}
可以改为(第一个天真的方法):
public static class MyFakeEnum
{
public static int Value1
{
get { return GetActualValue("Value1"); }
}
public static int Value2
{
get { return GetActualValue("Value2"); }
}
private static int GetActualValue(string name)
{
// Put here the code to read the actual value
// from your favorite source. It can be a database, a configuration
// file, the registry or whatever else. Consider to cache the result.
}
}
这将简单地提供所需的常量,但如果您需要MyFakeEnum
作为参数,则必须抛弃该类型的编译时检查。为了获得更好的解决方案,您可以遵循,例如,Microsoft对System.Drawing.Color
所做的(或多或少)。
public sealed class MyFakeEnum
{
public static readonly MyFakeEnum Value1 = new MyFakeEnum("Value1");
public static readonly MyFakeEnum Value2 = new MyFakeEnum("Value2");
private MyFakeEnum(string name)
{
_name = name;
}
public static implicit operator int(MyFakeEnum value)
{
return GetActualValue(value._name);
}
private string _name;
}
当然,您应该至少为Equals
,GetHashCode
和ToString
提供适当的覆盖。
<强>临强>
enum
的升级版。代码不会被破坏,您可能只需要重新编译。void DoSomething(MyFakeEnum value)
有效且调用者无法传递其他内容(请注意,这是其中一个原因,因为枚举被视为弱)。value == MyFakeEnum::Value1
。FlagsAttribute
语法。MyFakeEnum.Value1
。 <强>缺点强>
enum
的替代品,这不是问题,因为它也已修复)。使用此解决方案,您可以保存或多或少与标准枚举相同的语法。