通用类,只能采用某些类型

时间:2018-06-27 18:29:21

标签: c# generics c#-2.0

假设,我想创建一个仅可以将intdouble作为类型的泛型类。

public class A<T> where T: int, double
{
    public T property{get;set;}
}

例如:

A<int> i = new A<int>();
i.property = 10;

A<double> d = new A<double>();
d.property = 0.01;

但是,这不起作用。

我该怎么做?

我还有其他方法可以满足我的特定要求吗?

6 个答案:

答案 0 :(得分:4)

C#中不存在这样的约束。但是对于值类型,您可以使用struct作为一般约束。它仅允许非空值类型。

public class A<T> where T : struct
{
    public T property;
}

您可以在构造函数中添加运行时类型检查:

public class A<T> where T : struct
{
    public T property;
    public A()
    {
        if(typeof(T) != typeof(int) || typeof(T) != typeof(double))
        {
            throw new InvalidConstraintException("Only int or double is supported");
        }
    }
}

答案 1 :(得分:3)

您可以编写自己的包装程序,并为其使用基本接口。例如:

public class Integer : IMyNumber
{
    public int Value { get; set; }


    public Integer() { }
    public Integer( int value ) { Value = value; }


    // Custom cast from "int":
    public static implicit operator Integer( Int32 x ) { return new Integer( x ); }

    // Custom cast to "int":
    public static implicit operator Int32( Integer x ) { return x.Value; }


    public override string ToString()
    {
        return string.Format( "Integer({0})", Value );
    }
}


public interface IMyNumber
{
    // nothing needed
}

然后您可以编写您的通用类:

public class A<T> where T : IMyNumber
{
    public T property;
}

您可以使用它:

A<Integer> i = new A<Integer>();
i.property.Value = 10;

答案 2 :(得分:1)

您可以将private构造函数添加到A<T>类中,并声明两个相应的类:A_intA_double 内部,以便可以继承他们从A<T>开始-对他们成为“友好” A<T>。但是对于在该范围之外声明的类(Test类),由于private构造函数而无法直接创建,我们将不得不调用,但是不能。因此,实际上,您只有A<T>的两个可用变体,并带有编译时间不允许使用的通知:

public class A<T> where T : struct
{
    //constructor surely can have arguments
    private A()
    {
    }

    public T property { get; set; }
    //and other common stuff

    //each class declaration below we can treat like "where" constraint
    public class A_int : A<int> { }
    public class A_double : A<double> { }
}

//compile time error:
//'A<bool>.A()' is inaccessible due to its protected level
public class Test : A<bool>
{
}

用法:

using static NameSpaceName.A<int>;
//you should not care about <int> - it is only needed for compiler 
//and won't have any influence

var intVar = new A_int();
var doubleVar = new A_double(); 

//compile time error:
//'A<decimal>.A()' is inaccessible due to its protected level
var decimalVar = new A<decimal>(); 

答案 3 :(得分:0)

您可以通过使用带有静态方法的工作区并使构造函数内部化来实现。 但是,仅当A <>在其他库中时,此方法才有效。如果所有内容都在同一个库中,则此解决方案将无法工作。

public class Program
{
    public static void Main()
    {
        var a = A.CreateDecimal();
        a.property = 7;
    }
}

public class A<T>
{
    public T property;
    internal A()
    {
    }
}

public static class A
{
    public static A<decimal> CreateDecimal() => new A<decimal>();
    public static A<int> CreateInt() => new A<int>();
}

答案 4 :(得分:0)

据我对C#泛型的理解,您可以通过几种“模式”来设置泛型:

  • 不指定通用参数是什么,即对每种类型,基本类型等都开放。
  • 通过指定诸如where T : classwhere T : BaseClass甚至是where T : ISomeInterface之类的过滤器,您可以在其中指定传入的类型必须严格地是一个类,一个继承自BaseClass或分别实现ISomeInterface的类型。

据我所知,没有办法限制您可以使用的结构或基元。最好的选择是使用要使用的原始类型创建单独的实现。另外,您可以创建一个构造函数,以检查传入的类型是否与允许的类型匹配,以及是否引发异常。

public class MyGenericClass<T> 
{
    public MyGenericClass()
    {
        if(typeof(T) != typeof(int)) throw new Exception("You have passed an invalid type");
    }
}

希望这会有所帮助。

答案 5 :(得分:0)

如果您唯一的目标是防止A与<p style="background-color: #000"> <button> <svg width="25px" height="25px" xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 43.42 43.42"> <path d="M21.71,43.42A21.71,21.71,0,1,1,43.42,21.71,21.73,21.73,0,0,1,21.71,43.42ZM21.71,2A19.71,19.71,0,1,0,41.42,21.71,19.73,19.73,0,0,0,21.71,2Z" style="fill: rgb(255, 255, 255);"></path> </svg> </button>int以外的其他任何东西一起使用,则可以使用。 XML注释至少可以告诉潜在的开发人员它们有限。

deouble