Is there a way to enforce/limit the types that are passed to primitives? (bool, int, string, etc.)
Acum, știu că puteți limita parametrul de tip generic la o implementare de tip sau de interfață prin intermediul clauzei unde . Cu toate acestea, acest lucru nu se potrivește facturii pentru primitive (AFAIK), deoarece nu toate au un teren comun (cu excepția obiectului înainte de cineva spune!: P).
Deci, gândurile mele actuale sunt doar să-mi sparg dinții și să fac o instrucțiune comutator și să arunc o eroare ArgumentException la eșec.
EDIT 1:
Doar pentru a clarifica:
Definiția codului ar trebui să fie:
public class MyClass ....
Și instanțierea:
MyClass = new MyClass();//Legal
MyClass = new MyClass();//Legal
MyClass = new MyClass();//Illegal
MyClass = new MyClass();//Illegal (but looks awesome!)
EDIT 2
@Jon Limjap - Punct bun, și ceva ce mă gândeam deja .. Sunt sigur că există o metodă generică care poate fi utilizată pentru a determina dacă tipul este de valoare sau tip de referință.
Acest lucru ar putea fi util pentru a elimina instantaneu o mulțime de obiecte pe care nu vreau să le tratez (dar atunci trebuie să vă faceți griji cu privire la structurile care sunt utilizate, cum ar fi Dimensiune ) .. Problema interesantă nu? :)
Aici este:
where T : struct
Luat de la MSDN .
Sunt curios .. Ar putea fi făcut în. NET 3.x folosind metode de extensie? Creați o interfață și implementați interfața în metodele de extensie (care ar fi probabil mai puțin curat decât un comutator de grăsime bit). În plus, dacă mai trebuie să extindeți mai târziu la oricare tip personalizat ușor, aceștia pot implementa aceeași interfață, fără modificări necesare pentru codul de bază.
Voi ce credeți?
Vestea trista este ca lucrez in cadrul 2! : D
EDIT 3
Acest lucru a fost atât de simplu ca urmare a Pointerul lui Jon Limjaps .. Atât de simplu vreau aproape să plâng, dar este minunat deoarece codul funcționează ca un farmec!
Deci, iată ce am făcut (veți râde!):
bool TypeValid()
{
//Get the TypeCode from the Primitive Type
TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));
//All of the TypeCode Enumeration refer Primitive Types
//with the exception of Object and Empty (Null).
//Since I am willing to allow Null Types (at this time)
//all we need to check for is Object!
switch (code)
{
case TypeCode.Object:
return false;
default:
return true;
}
}
Apoi o mică metodă de utilitate pentru a verifica tipul și a arunca o excepție,
private void EnforcePrimitiveType()
{
if (!TypeValid())
throw new InvalidOperationException(
"Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name +
"' - this Class is Designed to Work with Primitive Data Types Only.");
}
Tot ce trebuie făcut este să apelați EnforcePrimitiveType () în constructorii de clase. Treaba făcuta! :-)
Singurul dezavantaj, aruncă doar o excepție la timpul de execuție (evident), mai degrabă decât timpul de design .. Dar asta nu este mare lucru și ar putea fi luat cu utilități ca FxCop (pe care nu o folosim la serviciu).
Mulțumiri speciale lui Jon Limjap pe aceasta!
public class Class1 where GenericType : struct
{
}
Aceasta părea să facă treaba.
Primitivele par să fie specificate în TypeCode
enumerare:
Poate că există o modalitate de a afla dacă un obiect conține codul TypeCode enum
fără a fi nevoie să îl deplasați la un anumit obiect sau să apelați GetType ()
sau typeof ()
?
Update It was right under my nose. The code sample there shows this:
static void WriteObjectInfo(object testObject)
{
TypeCode typeCode = Type.GetTypeCode( testObject.GetType() );
switch( typeCode )
{
case TypeCode.Boolean:
Console.WriteLine("Boolean: {0}", testObject);
break;
case TypeCode.Double:
Console.WriteLine("Double: {0}", testObject);
break;
default:
Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
break;
}
}
}
E încă un comutator urât. Dar este un loc bun pentru a începe!
Destul de mult ce a spus @Lars:
//Force T to be a value (primitive) type.
public class Class1 where T: struct
//Force T to be a reference type.
public class Class1 where T: class
//Force T to be a parameterless constructor.
public class Class1 where T: new()
Toate lucrările în .NET 2, 3 și 3.5.
Dacă puteți tolera utilizarea metodelor din fabrică (în locul constructorilor MyClass pe care i-ați cerut), puteți face întotdeauna ceva de genul:
class MyClass
{
private readonly T _value;
private MyClass(T value) { _value = value; }
public static MyClass FromInt32(int value) { return new MyClass(value); }
public static MyClass FromString(string value) { return new MyClass(value); }
//etc for all the primitive types, or whatever other fixed set of types you are concerned about
}
A problem here is that you would need to type MyClass
, which is annoying. There isn't a very good way around this if you want to maintain the private-ness of the constructor, but here are a couple of workarounds:
MyClass
. Make MyClass
inherit from MyClass
and nest it within MyClass
. Move the static methods to MyClass
. This will all the visibility work out, at the cost of having to access MyClass
as MyClass.MyClass
.MyClass
as given. Make a static class MyClass
which calls the static methods in MyClass
using MyClass
(probably using the appropriate type each time, just for giggles).MyClass
which inherits from MyClass
. (For concreteness, let's say MyClass
.) Because you can call static methods defined in a base class through the name of a derived class, you can now use MyClass.FromString
.Acest lucru vă oferă o verificare statică în detrimentul mai multor scrisori.
Dacă sunteți mulțumit de verificarea dinamică, aș folosi câteva variante ale soluției TypeCode de mai sus.
Puteți simplifica metoda EnforcePrimitiveType
utilizând typeof (PrimitiveDataType) .IsPrimitive
. Am pierdut ceva?
@Rob, Enum
va aluneca prin funcția TypeValid
, deoarece TypeCode
este Integer
. Am actualizat funcția de verificat și pentru Enum
.
Private Function TypeValid() As Boolean
Dim g As Type = GetType(T)
Dim code As TypeCode = Type.GetTypeCode(g)
' All of the TypeCode Enumeration refer Primitive Types
' with the exception of Object and Empty (Nothing).
' Note: must also catch Enum as its type is Integer.
Select Case code
Case TypeCode.Object
Return False
Case Else
' Enum's TypeCode is Integer, so check BaseType
If g.BaseType Is GetType(System.Enum) Then
Return False
Else
Return True
End If
End Select
End Function
Având o provocare similară, mă întrebam cum v-ați simțit despre Interfața IConvertible . Aceasta permite ceea ce solicită solicitantul și vă puteți extinde cu propriile implementări.
Exemplu:
public class MyClass
where TKey : IConvertible
{
//class intentionally abbreviated
}
Mă gândesc la asta ca la o soluție, cu toate că multe dintre cele sugerate făceau parte și din selecția mea.
Preocuparea mea este - cu toate acestea - este înșelătoare pentru dezvoltatorii potențiali care folosesc clasa ta?
Noroc - și mulțumiri.