Reputation: 2857
I want to create a constructor that only accepts primitive types, how can I do this?
Like this example:
public Test(PrimitiveType type)
{
}
I need do it in a constructor and it's optional, so I want to create a parameterless constructor and a constructor with the parameter.
Upvotes: 6
Views: 6827
Reputation: 10708
EDIT: I Was completely mistaken in my last answer. Please see the following
Type class does in fact bear an IsPrimitive property. This will allow you to check against the class data if it is primitive.
As with anything you need to take in more than one acceptable type, you'll need to make it generic, severely limiting some options at runtime.
public void SomeMethod<T>(T obj)
{
if(typeof(T).IsPrimitive == false) throw new ArgumentException("obj");
}
UPDATE: If this is a constructor, you can accept any object type. Otherwise, you'll have to make your class generic for that parameter
// Constructor for SomeClass
public SomeClass(object obj)
{
if(obj.GetType().IsPrimitive == false) throw new ArgumentException("obj");
}
EDIT: So this is still getting updates and I'd like to point out a very big reason why this sort of approach probably isn't good architecture; it's possible to construct new types that function like primitive types. System.Numerics has a bunch of these nonprimitive, mathematical, struct
types, my favorite being BigInteger, but more common being Vector2 or similar implementations.
Upvotes: 2
Reputation: 44449
I have given a very similar solution before but using a template you can generate multiple overloads that use the different types that you want (at compiletime).
<#@ template language="C#" #>
<#@ output extension=".cs" #>
<#@ import namespace="NamespaceProofOfConcept" #>
<#@ assembly name="$(TargetPath)" #>
<# Type[] types = new[] {
typeof(byte), typeof(short), typeof(int),
typeof(long), typeof(float), typeof(double),
typeof(bool), typeof(DateTime), typeof(char),
typeof(string)
};
#>
using System;
namespace NamespaceProofOfConcept {
public partial class Test {
<# foreach (var type in types) {
#>
public Test(<#= type.Name #> value) {
doConstructorStuff(value);
}
<#
} #>
private void doConstructorStuff(object o){
}
}
}
This will generate the following class:
using System;
namespace NamespaceProofOfConcept {
public partial class Test {
public Test(Byte value) {
doConstructorStuff(value);
}
public Test(Int16 value) {
doConstructorStuff(value);
}
public Test(Int32 value) {
doConstructorStuff(value);
}
public Test(Int64 value) {
doConstructorStuff(value);
}
public Test(Single value) {
doConstructorStuff(value);
}
public Test(Double value) {
doConstructorStuff(value);
}
public Test(Boolean value) {
doConstructorStuff(value);
}
public Test(DateTime value) {
doConstructorStuff(value);
}
public Test(Char value) {
doConstructorStuff(value);
}
public Test(String value) {
doConstructorStuff(value);
}
private void doConstructorStuff(object o){
}
}
}
Now you can only call this constructor with the types you defined (which are essentially the VB.NET primitive types).
You can add functionality to this by creating your own partial class which defines the behaviour:
namespace NamespaceProofOfConcept
{
public partial class Test
{
public void DoAThing()
{
System.Console.WriteLine("custom method!");
}
}
}
And you can test it out with the following code (which outputs "custom method!"):
static void Main(string[] args)
{
Test obj = new Test(true);
obj.DoAThing();
Console.ReadKey();
}
If you want even more "security", you can define the parameterless constructor as private inside your T4 template so it cannot be added unless the template is modified.
Upvotes: 1
Reputation: 12554
Depending upon what you want to achieve, you might want to look at so-called "convertible types", e.g. the types that implement IConvertible
interface, those are the following:
Boolean
, SByte
, Byte
, Int16
, UInt16
, Int32
, UInt32
, Int64
, UInt64
, Single
, Double
,Decimal
,DateTime
,Char
, and String
.So, as you see, this covers pretty much of what you'd like to achieve with primitive types.
So, by writing the method like that
public void Test(IConvertible primitive)
{
if (primitive is Double) ....
if (primitive is String) ....
}
you will confine your input types to the following ones (no structs etc).
Alternatively, you can also implement it as a generic method:
public void Test<T>(T primitive) where T : IConvertible
{
if (primitive is Double) ....
if (primitive is String) ....
}
Since you put this constrain, you can always convert your type to one, like:
public void Test<T>(T primitive) where T : IConvertible
{
var myval = Convert.ToDecimal(primitive);
....
}
Upvotes: 11
Reputation: 292555
There is no way to do it with a single overload¹ (but you could write overloads for each primitive type, of course). You can make it accept only value types, but then it will accept any struct
, not just primitive types.
¹ well, it's not possible to enforce it at compile time, but you can check the type at runtime and throw an exception of course...
Upvotes: 4