Search code examples
c#reflectiondelegatesfunc

Simplify passing nameof(someObject) and someObject as parameters to a method


I have a method where I'm currently passing in both someObject and nameof(someObject) since I'm using this method many times I'm wanting to simplify my code by finding a way to only pass in the object once but if I do the nameof() inside the method I'm obviously not going to get the name I want.

What I have currently is something like this:

public record ResourceObject
{
    public string Name { get; init; }
    public byte[] File { get; init; }
    public string Content { get; init; }

    public ResourceObject(string name, byte[] file)
    {
        Name = name;
        File = file;
        Content = Encoding.Default.GetString(file);
    }
}

Where the use looks like this:

var test = new ResourceObject(nameof(Properties.Resources.SomeResource), Properties.Resources.SomeResource)

Ideally, I'd like to get the use to look like this(I don't think this is possible):

var test = new ResourceObject(Properties.Resources.SomeResource)

I did find a post that shows getting the name like this but then I can't get the object itself:

public record ResourceObject
{
    public string Name { get; init; }
    public byte[] File { get; init; }
    public string Content { get; init; }

    private ResourceObject(string name, byte[] file)
    {
        Name = name;
        File = file;
        Content = Encoding.Default.GetString(file);
    }
    public static ResourceObject New<T>(Expression<Func<T>> property)
    {
        var name = (property.Body as MemberExpression).Member.Name;
        var file = ???; //I can't figure out how to get the object itself here
        return new(name, file);
    }
}

The use for that looks like this (which would be great improvement over what I if I could get it to work):

var test = ResourceObject.New(() => Resources.TradeEngineSettings_Base);


Solution

  • This is what ultimately worked for me.

    public record ResourceObject<T>
    {
        public string Name { get; }
        public T Object { get; }
        public string Content { get; }
    
        public ResourceObject(T @object, [CallerArgumentExpression(nameof(@object))] string name = null)
        {
            Name = name.Split('.', StringSplitOptions.RemoveEmptyEntries)[^1];
            Object = @object;
            if (@object?.GetType() == typeof(byte[]))
            {
                Content = Encoding.Default.GetString(@object as byte[] ?? Array.Empty<byte>());
            }
        }
    }
    

    To keep Name more similar to a nameof() behavior, name is split on '.' and only takes the last item in the array.