Почему не разрешается иметь общий класс, как это:Как смешивать общие и реальные типы
class SomeClass<T, int> { ..... }
также можно заставить некоторый тип T, чтобы быть числовыми и поддерживают основные операторы, такие как +, -, * а также /.
Почему не разрешается иметь общий класс, как это:Как смешивать общие и реальные типы
class SomeClass<T, int> { ..... }
также можно заставить некоторый тип T, чтобы быть числовыми и поддерживают основные операторы, такие как +, -, * а также /.
Параметр generic T
позволяет неспецифически указывать тип параметра, используемый классом.
Если вы хотите использовать int
, используйте int
внутри класса. Если вы хотите указать, что что-то в классе должно быть int
, то сделайте это с помощью параметра public или конструктору.
Поддержка операторов будет осуществляться по типу, в котором он сам передается. Если вы переопределили оператор для типа, то он будет судить его после использования в классе. Вы не можете сделать это по неизвестному родовому признаку.
Поскольку дженерики не совпадают с шаблонами 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
. Но это можно сделать, используя это как отправную точку.
Для второй части вопроса вы можете сделать:
class MyClass<T> where T : IEquatable<T>, IComparable<T>
Там нет родительского класса для всех числовых значений, Буц они применяют эти интерфейсы.
Один вопрос на вопрос, пожалуйста. –
Что означало бы 'int' в объявлении этого класса? Общее объявление объявляет параметры типа * * и 'int' не может быть параметром типа, хотя он * может * быть аргументом типа. Если вы объясните, что вы пытаетесь сделать, это поможет. –
@ Не используйте какое-либо конкретное использование для этого int, просто сравнивая с шаблонами C++. – NDeveloper