2011-05-24 11 views
4

Почему не разрешается иметь общий класс, как это:Как смешивать общие и реальные типы

class SomeClass<T, int> { ..... } 

также можно заставить некоторый тип T, чтобы быть числовыми и поддерживают основные операторы, такие как +, -, * а также /.

+1

Один вопрос на вопрос, пожалуйста. –

+0

Что означало бы 'int' в объявлении этого класса? Общее объявление объявляет параметры типа * * и 'int' не может быть параметром типа, хотя он * может * быть аргументом типа. Если вы объясните, что вы пытаетесь сделать, это поможет. –

+0

@ Не используйте какое-либо конкретное использование для этого int, просто сравнивая с шаблонами C++. – NDeveloper

ответ

2

Параметр generic T позволяет неспецифически указывать тип параметра, используемый классом.

Если вы хотите использовать int, используйте int внутри класса. Если вы хотите указать, что что-то в классе должно быть int, то сделайте это с помощью параметра public или конструктору.

Поддержка операторов будет осуществляться по типу, в котором он сам передается. Если вы переопределили оператор для типа, то он будет судить его после использования в классе. Вы не можете сделать это по неизвестному родовому признаку.

3

Поскольку дженерики не совпадают с шаблонами C++; которые допускают частичную специализацию.

Конечно, вы можете иметь это:

public class Generic<T, U> {} 

public class Generic2<T> : Generic<T, int> {} 

До тех пор, как и любые общие ограничения, присутствующие на T в первом родового, по крайней мере неоднократные или более ограничительные на второй.

Что касается ограничений, которые вы просите, нет, вы не можете. Однако вы можете ограничить типы значений (where T : struct, конечно); но это не ограничивает числовое значение.

Операторы не включены как часть контракт класса (либо основание или интерфейс) из-за того, что операторы определены статический и для выражения a op b, могут появиться на любом из двух типов T(a) или T(b).

В результате невозможно определить ограничения типов на их основе.

Однако, вы можете определить свой собственный контракт - как это (наивная и полностью неполную реализацию здесь, просто чтобы продемонстрировать, in a wall of code(tm)):

(Проверьте родовое в самом конце, чтобы увидеть, что он работает)

public abstract class MyNumeric 
{ 
    public abstract object ValueObject { get; } 
    public abstract MyNumeric Add(MyNumeric other); 
    public abstract MyNumeric Substract(MyNumeric other); 
    public abstract MyNumeric Multiply(MyNumeric other); 
    public abstract MyNumeric Divide(MyNumeric other); 

    public static MyNumeric operator +(MyNumeric a, MyNumeric b) 
    { 
    return a.Add(b); 
    } 
    public static MyNumeric operator -(MyNumeric a, MyNumeric b) 
    { 
    return a.Substract(b); 
    } 
    public static MyNumeric operator *(MyNumeric a, MyNumeric b) 
    { 
    return a.Multiply(b); 
    } 
    public static MyNumeric operator /(MyNumeric a, MyNumeric b) 
    { 
    return a.Divide(b); 
    } 
    //etc 
} 

public abstract class MyNumeric<T> : MyNumeric 
    where T : struct 
{ 
    public override object ValueObject { get{ return this.Value;}} 
    public new T Value { get; private set; } 
    public MyNumeric(T value) { Value = value; } 
} 

public class MyInt : MyNumeric<int> 
{ 
    public MyInt(int value) : base(value) { } 
    public override MyNumeric Add(MyNumeric other) 
    { 
    //could be really crafty here and use an interface instead that 
    //gives access to the Value part only - that way you could 
    //have MyDouble, for example, implement INumeric<int> explicitly 
    //via a c# explicit conversion. 
    MyNumeric<int> otherInt = other as MyNumeric<int>; 
    if (otherInt == null) 
     throw new ArgumentException(
     "Need to handle numeric promotion/demotion for all types", "other"); 
    return new MyInt(Value + otherInt.Value); 
    } 
    public override MyNumeric Divide(MyNumeric other) 
    { 
    throw new NotImplementedException(); 
    } 
    public override MyNumeric Multiply(MyNumeric other) 
    { 
    throw new NotImplementedException(); 
    } 
    public override MyNumeric Substract(MyNumeric other) 
    { 
    throw new NotImplementedException(); 
    } 
} 

public class MyGeneric<TNumeric> where TNumeric : MyNumeric 
{ 
    public TNumeric WillNowCompile(TNumeric a, TNumeric b) 
    { 
    //cast is still required on the result. 
    //however - you can set the return type to MyNumeric instead if you want. 
    return (TNumeric)(a + b); 
    } 

    public TNumeric AnotherOne<TNumeric2>(TNumeric a, TNumeric2 b) 
    where TNumeric2 : MyNumeric 
    { 
    return (TNumeric)(a/b); 
    } 
} 

как я уже говорил в коде, однако, вы должны подумать, как справиться с подобными ситуациями int + double. Но это можно сделать, используя это как отправную точку.

0

Для второй части вопроса вы можете сделать:

class MyClass<T> where T : IEquatable<T>, IComparable<T> 

Там нет родительского класса для всех числовых значений, Буц они применяют эти интерфейсы.

Смежные вопросы