0

I have a static class defined like this:

public static class JobStatus
{ 
    public const string Completed = "Completed";
    public const string Failed = "Failed";
    public const string Stopped = "Stopped";
}

(this is actually an external library, so can't change this)

In my non-static class I want a member of that class to ensure that you can only declare it of that "type"

public class JobOutput
{
    public string Output { get; set; }

    public string OutputError { get; set; }

    public JobStatus JobStatus { get; set; }
}

Error: 'JobStatus': static types cannot be used as return types / 'JobStatus': static types cannot be used as parameters

Yeye I know your eyes are bleeding, but I hope you get the point - how can I ensure and achieve a form of type-safety for my JobStatus property?

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Morten_564834
  • 1,479
  • 3
  • 15
  • 26

2 Answers2

1

You can't, because all JobStatus does is contain some members who hold strings. So you'll have to define your JobStatus property as a string as well.

There's no compile-time safety for strings, it could've been an enum instead.

You could add a method SetJobStatus(string status) to your JobOutput class and make JobStatus's setter private. Then in that method, you check (using reflection) whether the status string is present in one of the static class JobStatus's public const fields. Or you could implement the same in the setter.

See How can I get all constants of a type by reflection? for information on how to do that. But that's not compile-time safety, but runtime.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
1

You could wrap JobStatus to make it "type safe" but it looks like a bit of an overkill:

public sealed class JobStatusWrapper
{
     public static readonly JobStatusWrapper Completed 
         = new JobStatusWrapper(JobStatus.Completed);

     public static readonly JobStatusWrapper Failed
         = new JobStatusWrapper(JobStatus.Failed);

     public static readonly JobStatusWrapper Stopped
         = new JobStatusWrapper(JobStatus.Stopped);

     private readonly string description;
     private JobStatusWrapper(string description) {
         Debug.Assert(!string.IsNullOrEmpty(description));
         this.description = description; }

     public static implicit operator string(JobStatusWrapper status)
         => status.description;
}

And now you'd use it:

public class JobOutput
{
    //...
    public JobStatusWrapper JobStatus { get; set; }
}

And there is no way to pass in or get a JobStatusWrapper that doesn't have one of the underlying values defined in JobStatus (except null). Also, the implicit operator makes the wrapper usable anywhere the JobStatus options are.

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • Thanks for the input! learned some new stuff there. But yes as @codecaster said the library could change, so i'd be even greater if it were dynamic. I don't think it will change though, so might be wasted effort. In anycase thanks! – Morten_564834 Nov 14 '18 at 11:07