C# 使用外部dll中的枚举
我有一个项目,我正在工作,将涉及创建一个DLL,将跨多个其他网站使用。在这个DLL中,我们需要引用大约10个枚举。但是,这些枚举的值对于使用DLL的每个站点都是不同的。例如:C# 使用外部dll中的枚举,c#,reflection,dll,enums,C#,Reflection,Dll,Enums,我有一个项目,我正在工作,将涉及创建一个DLL,将跨多个其他网站使用。在这个DLL中,我们需要引用大约10个枚举。但是,这些枚举的值对于使用DLL的每个站点都是不同的。例如: public enum MyEnum { Value1, Value2 } MyBase.dll可能有一个MyClass类,其属性类型为MyEnum 然后在MySite中引用MyBase.dll。MyStie还将引用MyEnums.dll,其中将包含MyEnum类型的值 有没有办法做到这一点?在构建MyB
public enum MyEnum
{
Value1,
Value2
}
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;
}
}
我想能够做的是定义各个项目中状态的可能值。所以在这个DLL中,我永远不会引用状态枚举中可能存在的值,我只需要知道它存在
我希望这能更清楚地说明我要做的事情。如果您希望每个客户端看到不同的枚举值(在不同的程序集版本中),那么使用枚举是一个糟糕的解决方案-更改将破坏客户端代码 使用枚举可能会起作用(只要枚举名称和程序集名称相同且程序集没有签名)-您可以交换程序集。但是,如果在代码中的任何地方使用了一个值,而该值最后不在那里,那么最终将出现一个异常。此外,您还可以使用显式编号来对值进行编号,以确保不同值的不同子集不会以不同值的相同编号或相同值的不同编号结束 请考虑使用动态构建的集合,例如列表、词典或数据库表或只是将具有相同枚举值超集的相同程序集提供给每个人,让用户决定哪些值与他们相关(可能会使用重要的前缀作为约定) 或者你可以把两者结合起来 为每个站点生成一个不同的结构(不同的类型名称(或命名空间)和程序集名称),该结构具有不同的属性(根据站点的配置文件),并为接受该结构的服务生成一个主结构。让所有的结构实现相同的接口,您希望收到
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();
}
}
或:
这样你就:
首先,你必须决定把常数放在哪里。然后可以将
enum
转换为静态属性
例如:
public enum MyEnum
{
Value1,
Value2
}
可以更改为(第一种简单方法):
这将简单地提供所需的常量,但如果需要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
提供适当的overide
Pro- 它可以是现有
枚举的升级。代码不会被破坏,您可能只需要重新编译
- 可以将其用作强类型参数。例如:
是有效的,调用方不能传递其他内容(请注意,这是原因之一,因为枚举被认为是弱的)void DoSomething(MyFakeEnum值)
- 如果实现了所有必需的运算符,则可以使用常规语法进行比较:
value==MyFakeEnum::Value1
- 使用少量代码,您甚至可以实现
语法FlagsAttribute
- 您不会更改枚举的常规语法:
MyFakeEnum.Value1
- 您可以在类型之间实现任意数量的隐式/显式转换运算符,并且任何转换都将是安全的,并在完成时进行检查(对于标准枚举,情况并非如此)
- 您没有可以被更改打断的硬编码字符串,并且在它们导致运行时错误(是的,运行时)之前不会被捕获。例如,使用字典如果要更改定义,则必须在所有代码中搜索该字符串
- 第一个实现更长,因为您必须编写支持代码(但对于任何新值,您只需添加一行新行)
- 值列表是固定的,必须在编译时知道(如果您正在搜索
的替换项,则这不是问题,因为它也是固定的)enum
使用此解决方案,您可以或多或少地保存与标准枚举相同的语法。我不同意您的解决方案,但是,至少现在它可以编译(添加缺少的类型)。@DannyVarod是的,第一个示例非常幼稚!我还在编辑答案以提供更多选项。谢谢你,我确实在声明中吃了“int”!实际上有一个名为Tarantino的开源项目使用了这种方法——请参阅。@David nice projec
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;
}