我有一个名为GenericItem的类(第一次使用泛型),假设我想将两个项目相乘,如果它们是整数类型,你可以看到我在方法returnCounterMultiply
中尝试它,但它虽然我试图转换它们并检查它们是否为整数类型,但是不允许我将它们相乘。
namespace Components
{
public class GenericItem<T>
{
private T data;
private T counter;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem(){}
public GenericItem(T _data)
{
data = _data;
}
public T returnCounterMultiply(T value)
{
int c = 0;
int d = 0;
if (counter.GetType() == typeof(int) && value.GetType() == typeof(int))
{
//cant multiply two of type T, why if i am converting to int?.
return (T)Convert.ChangeType(counter, typeof(Int32)) * (T)Convert.ChangeType(value, typeof(Int32));
}
return value;
}
}
}
我很感激对此的一些解释,因为这是我第一次开展这项工作(这只是一个用于理解这个GENERICS INTRO和此GENERICS CLASSES的示例课程,但仍然无法理解它
答案 0 :(得分:2)
在我看来,在这种情况下使用泛型是一种矫枉过正的行为。
通用约束支持以下内容会很好:
// T parameter is a type which overloads "+" operator...
where T : +
在你的具体案例中,我会说你以错误的方式行事。为什么不创建一个类来实现类型为int
的数学运算?
当T
参数(或任何其他参数,当然......)可以被约束为接收具有以下类型的类型时,泛型更好地工作:
T
必须是类而不是结构... 当你使用泛型需要进行类型转换时遇到问题时,我相信你已经打败了泛型!
答案 1 :(得分:2)
你的问题与泛型无关,但基本的C#强制转换:
//cant multiply two of type T, why if i am converting to int?.
return
(T)Convert.ChangeType(counter, typeof(Int32))
*
(T)Convert.ChangeType(value,typeof(Int32));
你没有乘以int但是T - 和T是泛型类型你只能使用在你的泛型约束中定义的方法,你没有,所以没有相乘。
如果你想乘以int,那么这样做:
(T) (
((Int32)Convert.ChangeType(counter, typeof(Int32)))
*
((Int32)Convert.ChangeType(value,typeof(Int32)))
);
看到区别?
基本上在你的代码中你在乘法中处理T,这里我处理Int32。事实上,如果T是Int32(正如你之前在IF语句中测试的那样),你可以跳过转换和转换:
(T) (
((Int32)counter)
*
((Int32)value)
);
现在,仿制药是数学的一个不好的例子,因为你不能在泛型上使用操作 - 遗憾的是。这是对这个概念的滥用,但我认为这是一个学习练习,因此我的答案集中在那一部分。
答案 2 :(得分:2)
我看不到你想要实现的目标,但如果你必须这样做,我认为你必须使用一个界面:
public interface IMultiplyable<T>
{
T Multiply(T x);
}
public class Int : IMultiplyable<Int>
{
private int _data { get; set; }
public Int(int data)
{
_data = data;
}
public Int Multiply(Int x)
{
return new Int(_data * x._data);
}
public override string ToString()
{
return _data.ToString();
}
}
public class GenericItem<T> where T : IMultiplyable<T>
{
private T data;
private T counter;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem() { }
public GenericItem(T _data)
{
data = _data;
}
public T returnCounterMultiply(T value)
{
return Data.Multiply(value);
}
public override string ToString()
{
return Data.ToString();
}
}
用法:
var a = new GenericItem<Int>(new Int(4));
MessageBox.Show(a.returnCounterMultiply(new Int(5)).ToString()); //20
答案 3 :(得分:1)
您可以这样做:
public class GenericItem<T>
{
private T data;
public T Data
{
get { return data; }
set { data = value; }
}
public GenericItem(){}
public GenericItem(T _data)
{
data = _data;
}
private Dictionary<Type, Delegate> operations =
new Dictionary<Type, Delegate>()
{
{ typeof(int), (Func<int, int, int>)((x, y) => x * y) },
{ typeof(string), (Func<string, string, string>)((x, y) => x + " " + y) },
};
public T returnCounterMultiply(T value)
{
if (operations.ContainsKey(typeof(T)))
{
var operation = (Func<T, T, T>)(operations[typeof(T)]);
return operation(data, value);
}
return value;
}
}
你只需要在字典中为每个你想要使用的有效类型定义一个操作,它就可以在没有任何类型转换的情况下工作(除了转换为Func
)。
我有这些测试结果:
var gii = new GenericItem<int>(42);
var xi = gii.returnCounterMultiply(2);
// xi == 84
var gis = new GenericItem<string>("Foo");
var xs = gis.returnCounterMultiply("Bar");
// xs == "Foo Bar"
答案 4 :(得分:0)
我也尝试了一次,并且必须发现没有很好的方法来使用泛型。你不能像在C ++中那样通用。
作为替代方案,您可以包装数据类型并使用通用接口:
interface IMathOps
{
object Value { get; }
void Add(IMathOps other);
// other methods for substraction etc.
}
class IntWrapper : IMathOps
{
public int value;
public void Add(IMathOps other)
{
if(other is IntWrapper)
{
this.value += (int)other.Value;
}
}
public object Value { get { return this.value; } }
}
// class FloatWrapper : IMathOps ...
答案 5 :(得分:-3)
我认为你应该使用where (generic type constraint)。因此,如果T不是int,它将在编译时给出错误。
public T returnCounterMultiply(T value) where T : int
{
int c = 0;
int d = 0;
return c*d;
}