Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#:接口中的枚举_C#_Generics_Interface_Enums - Fatal编程技术网

C#:接口中的枚举

C#:接口中的枚举,c#,generics,interface,enums,C#,Generics,Interface,Enums,我已经看到了一些类似于这个问题的线索,但没有一个真正回答了我想问的问题 对于初学者来说,不幸的是,我正在使用现有的API代码,虽然可能有更好的方法来完成我所要求的,但我仍然坚持这样做,因为向后兼容性是不可协商的 我有一个响应类,当前包含错误代码的枚举和字符串描述。错误代码定义了一组相当好且完整的响应,这些响应在语义上都与使用它们的操作相耦合 不幸的是,我现在必须为一组类似的API对象添加一个不同的工作流,这将需要一个字符串描述,这很好,但也需要一个由一组完全不相关的错误代码组成的枚举错误代码。错

我已经看到了一些类似于这个问题的线索,但没有一个真正回答了我想问的问题

对于初学者来说,不幸的是,我正在使用现有的API代码,虽然可能有更好的方法来完成我所要求的,但我仍然坚持这样做,因为向后兼容性是不可协商的

我有一个响应类,当前包含错误代码的枚举和字符串描述。错误代码定义了一组相当好且完整的响应,这些响应在语义上都与使用它们的操作相耦合

不幸的是,我现在必须为一组类似的API对象添加一个不同的工作流,这将需要一个字符串描述,这很好,但也需要一个由一组完全不相关的错误代码组成的枚举错误代码。错误代码(以及对象模型的其他方面)将在许多相同的类中使用,因此最好有一个接口,这样我就可以通过相同的框架运行对象

这里的目的是签订一份合同,上面写着“我有一个错误代码,以及该错误代码的描述。”

但是,据我所知,无法将项添加到接口,例如

public interface IError
{
    enum ErrorCode;
    string Description;
}
也没有表达的方式

public interface IError<T> where T: enum
{
    T ErrorCode;
    string Description;
}
公共接口错误,其中T:enum
{
错误码;
字符串描述;
}

以前有人碰到过这样的事情吗?

是的,我碰到过这样的事情。不是在这种特殊情况下,而是在其他堆栈溢出问题中。(我不打算以重复的方式结束这一次,因为它略有不同。)

可以表达您的通用接口—只是不能用C#。你可以在IL中毫无问题地完成它。我希望在C#5中可以消除这个限制。据我所见,C#编译器实际上完全正确地处理了约束

如果您真的想将此作为一个选项,您可以使用类似于中的代码,我有一个库,它公开了各种方法,具有这种难以生成的约束。它有效地使用了IL重写——这很粗糙,但它对嗯有效,而且可能对你也有效。不过,您可能希望将接口放入一个单独的程序集中,这会有点尴尬


当然,您可以让您的界面只包含
T:struct
。。。这并不理想,但至少会在某种程度上限制类型。只要你能确保它没有被滥用,那就相当好了。

无法编写
公共接口IError,其中t:enum
是我们多年来一直抱怨的问题。到目前为止,在这方面没有任何进展


我通常会编写
公共接口IError
,并给实现者留下一条提示,T必须是一个枚举。

如果我理解您想要做什么,那么是的,没有办法定义一个接口,该接口包含一个非特定的枚举作为其成员之一。第二个示例很接近,但您仅限于将
T
的类型约束为
struct
,这将允许任何值类型。在这一点上,您只需依赖接口的正确使用知识,让人们知道
T
的预期类型应该是枚举。通过将
T
定义为
TEnum
TErrorValue
,您可能会让它更清晰一些:

public interface IError<TEnum> where T: struct
{
    T ErrorCode;
    string Description;
}
公共接口错误,其中T:struct
{
错误码;
字符串描述;
}

正如Jon Skeet提到的,基本IL支持将泛型约束为枚举,但是C#不允许您利用它

然而,F#确实允许这种约束。此外,如果接口是在F#中定义的,则约束将在实现该接口的C#代码中强制执行。如果您愿意在解决方案中混合使用各种语言,类似这样的方法应该可以很好地工作:

type IError<'T when 'T :> System.Enum and 'T : struct> =
    abstract member Error : 'T
    abstract member Description : string
键入IError System.Enum和'T:struct>=
抽象成员错误:“T”
抽象成员描述:字符串

如果将其放在F#项目中并从C#项目中引用,则实现该接口的C#代码在尝试将其与非枚举类型一起使用时将导致C#编译器错误。

您可以使用稍微不同的方法:

public interface IError
{
    Enum ErrorCode;
    string Description;
}
System.Enum
是所有枚举的基类,因此应该由它来处理,但它远没有表现力。

这里正确的方法是构建您自己的枚举类和它的基枚举类。例如

public class ErrorFlag // base enum class
{
    int value;

    ErrorFlag() 
    {

    }

    public static implicit operator ErrorFlag(int i)
    {
        return new ErrorFlag { value = i };
    }

    public bool Equals(ErrorFlag other)
    {
        if (ReferenceEquals(this, other))
            return true;

        if (ReferenceEquals(null, other))
            return false;

        return value == other.value;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as ErrorFlag);
    }

    public static bool operator ==(ErrorFlag lhs, ErrorFlag rhs)
    {
        if (ReferenceEquals(lhs, null))
            return ReferenceEquals(rhs, null);

        return lhs.Equals(rhs);
    }

    public static bool operator !=(ErrorFlag lhs, ErrorFlag rhs)
    {
        return !(lhs == rhs);
    }

    public override int GetHashCode()
    {
        return value;
    }

    public override string ToString()
    {
        return value.ToString();
    }
}

public interface IError
{
    ErrorFlag ErrorCode;
    string Description;
}
现在,不要拥有自己的错误枚举,而是编写自己的
ErrorFlag

public sealed class ReportErrorFlag : ErrorFlag
{
    //basically your enum values
    public static readonly ErrorFlag Report1 = 1;
    public static readonly ErrorFlag Report2 = 2;
    public static readonly ErrorFlag Report3 = 3;

    ReportErrorFlag() 
    {

    }
}

public sealed class DataErrorFlag : ErrorFlag
{
    //basically your enum values
    public static readonly ErrorFlag Data1 = 1;
    public static readonly ErrorFlag Data2 = 2;
    public static readonly ErrorFlag Data3 = 3;

    DataErrorFlag() 
    {

    }
}

// etc
现在你的主要课程是:

public class ReportError : IError
{
    // implementation
}

public class DataError : IError
{
    // implementation
}
或其他方式,

public class ErrorFlag // base enum class
{
    internal int value { get; set; }

    public bool Equals(ErrorFlag other)
    {
        if (ReferenceEquals(this, other))
            return true;

        if (ReferenceEquals(null, other))
            return false;

        return value == other.value;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as ErrorFlag);
    }

    public static bool operator ==(ErrorFlag lhs, ErrorFlag rhs)
    {
        if (ReferenceEquals(lhs, null))
            return ReferenceEquals(rhs, null);

        return lhs.Equals(rhs);
    }

    public static bool operator !=(ErrorFlag lhs, ErrorFlag rhs)
    {
        return !(lhs == rhs);
    }

    public override int GetHashCode()
    {
        return value;
    }

    public override string ToString()
    {
        return value.ToString();
    }
}

public interface IError<T> where T : ErrorFlag
{
    T ErrorCode { get; set; }
    string Description { get; set; }
}

//enum classes
public sealed class ReportErrorFlag : ErrorFlag
{
    //basically your enum values
    public static readonly ReportErrorFlag Report1 = new ReportErrorFlag { value = 1 };
    public static readonly ReportErrorFlag Report2 = new ReportErrorFlag { value = 2 };
    public static readonly ReportErrorFlag Report3 = new ReportErrorFlag { value = 3 };

    ReportErrorFlag()
    {

    }
}

public sealed class DataErrorFlag : ErrorFlag
{
    //basically your enum values
    public static readonly DataErrorFlag Data1 = new DataErrorFlag { value = 1 };
    public static readonly DataErrorFlag Data2 = new DataErrorFlag { value = 2 };
    public static readonly DataErrorFlag Data3 = new DataErrorFlag { value = 3 };

    DataErrorFlag()
    {

    }
}

//implement the rest
public class ErrorFlag//基本枚举类
{
内部int值{get;set;}
公共布尔等于(ErrorFlag其他)
{
if(ReferenceEquals(this,other))
返回true;
if(ReferenceEquals(null,其他))
返回false;
返回值==other.value;
}
公共覆盖布尔等于(对象对象对象)
{
返回等于(obj作为ErrorFlag);
}
公共静态布尔运算符==(ErrorFlag lhs、ErrorFlag rhs)
{
if(ReferenceEquals(lhs,null))
返回ReferenceEquals(rhs,null);
返回lhs等于(rhs);
}
公共静态布尔运算符!=(ErrorFlag lhs,ErrorFlag rhs)
{
返回!(lhs==rhs);
}
公共覆盖int GetHashCode()
{
返回值;
}
公共重写字符串ToString()
{
返回值.ToString();
}
}
公共接口IError,其中T:ErrorFlag
{
错误代码{get;set;}
字符串说明{get;set;}
}
//枚举类
公共密封类ReportErrorFlag:ErrorFlag
{
//基本上你的枚举值
public static readonly ReportErrorFlag Report1=new ReportErrorFlag{value=1};
公共静态只读Repor