Jag har skapat en klass som ser ut som följer: Nu är jag inte hemma på C#, men betyder <b>where T : struct</b> att T skall vara en struktur? Hur hade du tänkt dig att datorn skulle omvandlar ett tal (float eller short) till en ospecificerad struktur? <b>where T : struct</b> betyder att T måste vara en Value type, vilket både short och float är som du märker så funkar det inte. Gissar att det har att göra med att kompilatorn inte kan verifiera att det du försöker göra är giltigt. Problemet är att T är vilken värdetyp som helst. Om man expanderar den ena raden som blir fel med T = bool så blir den som följer:Cannot convert type 'float' to 'T' vid användning av Generic
sealed class LLDataPoint<T> : where T : struct
{
private ushort m_div;
/// <summary>
/// Värdet på datapunkten
/// </summary>
public T Value
{
get { return m_value; }
}
private T m_value;
/// <summary>
/// Värdet på datapunkten i råformat
/// </summary>
public ushort ValueRaw
{
get { return m_valueRaw; }
set
{
m_valueRaw = value;
//Om värdet är ett flyttal, dividera heltalet med divideringsfaktor
if (m_value is float)
// ERROR: Cannot convert type 'float' to 'T'
m_value = (T)((float)m_valueRaw / m_div);
else
// ERROR: Cannot convert type 'short' to 'T'
m_value = (T)m_valueRaw;
}
}
private ushort m_valueRaw;
/// <summary>
/// Konstruktor
/// </summary>
/// <param name="div">Divideringsfaktor. Om <see cref="T"/> inte är <see cref="float"/> måste div vara 1</param>
public LLDataPoint(ushort div)
{
if (!(m_value is float) && div != 1 || div == 0)
throw new ArgumentOutOfRangeException("div");
m_div = div;
}
}
}
Den ska användas för att tillhandaha värden jag får från ett annat system. Detta värde får jag på formatet ushort och detta ska sedan divideras för att få det i flyttalsformat. Divideringsfaktorn variera och vissa tal ska fortsätta vara i formatet short.
Men när jag försöker kompilera det får jag felmeddelandena "Cannot convert type 'float' to 'T'" och "Cannot convert type 'short' to 'T'"
Sv: Cannot convert type 'float' to 'T' vid användning av Generic
Sv:Cannot convert type 'float' to 'T' vid användning av Generic
Sv: Cannot convert type 'float' to 'T' vid användning av Generic
Sv: Cannot convert type 'float' to 'T' vid användning av Generic
<code>m_value = (bool)((float)m_valueRaw / m_div);</code>
För att kunna använda generics för denna klass bör du ta bort den typberoende koden från klassen LLDataPoint och skapa typade klasser som ärver från LLDataPoint. Den typberoende koden lägger du i en abstract metod som implementeras i de ärvande typade klasserna. Det där var inte helt tydligt, men jag skyller på att det är sent och att mitt snabbhackade exempel nedan kan ge lite mer info om hur jag menar.
<code>
class FloatDataPoint : LLDataPoint<float>
{
public FloatDataPoint(ushort div) : base(div)
{}
protected override float CalculateValue(ushort rawValue, int div)
{
return ((float)rawValue / div);
}
}
class UShortDataPoint : LLDataPoint<ushort>
{
public UShortDataPoint(ushort div) : base(div)
{}
protected override ushort CalculateValue(ushort rawValue, int div)
{
return rawValue;
}
}
abstract class LLDataPoint<T> where T : struct
{
private ushort m_div;
/// <summary>
/// Värdet på datapunkten
/// </summary>
public T Value
{
get { return m_value; }
}
private T m_value;
/// <summary>
/// Värdet på datapunkten i råformat
/// </summary>
public ushort ValueRaw
{
get { return m_valueRaw; }
set
{
m_valueRaw = value;
m_value = CalculateValue(m_valueRaw, m_div);
}
}
private ushort m_valueRaw;
protected abstract T CalculateValue(ushort rawValue, int div);
/// <summary>
/// Konstruktor
/// </summary>
/// <param name="div">Divideringsfaktor. Om <see cref="T"/> inte är <see cref="float"/> måste div vara 1</param>
public LLDataPoint(ushort div)
{
if (!(m_value is float) && div != 1 || div == 0)
throw new ArgumentOutOfRangeException("div");
m_div = div;
}
}
</code>