简体   繁体   中英

Templatized values in AssemblyInfo.cs? Or referring to other values from AssemblyInfo.cs?

I have several C# projects that are in some sense a unit. There are several common AssemblyInfo attributes that make sense to share among them (for example company name). So I made a shared file that all projects include, containing (for example) AssemblyCompany :

[assembly: AssemblyCompany("Acme Inc.")]

And I removed the corresponding attributes from each project's individual AssemblyInfo.cs.

This all worked well, but I'd like to go a step further in one case: copyright. The first year of publication varies from project to project, and so they really should have different copyright strings. So I'd like to do something like this in the shared file:

[assembly: AssemblyCopyright(string.Format("Copyright {$0} Acme Inc.", Acme.AssemblyInfo.FirstPublicationYear)]

And then have each individual project defining its own particular Acme.AssemblyInfo.FirstPublicationYear .

I have taken a couple different shots in the dark. First, I just tried defining a const in a static class in a project's AssemblyInfo.cs:

namespace Acme
{
    public static class AssemblyInfo
    {
        public const int FirstPublicationYear = 2015;
    }
}

This results in the error "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type". So I tried making an attribute class:

namespace Acme
{
    using System;

    [AttributeUsage(AttributeTargets.Assembly)]
    public class FirstPublicationYearAttribute : Attribute
    {
        private int year;

        public FirstPublicationYearAttribute(int year)
        {
            this.year = year;
        }
    }
}

Added that attribute to an individual project's AssemblyInfo.cs:

[assembly: Acme.FirstPublicationYear(2015)]

But I'm not sure how to (or even if I can) appropriately change the AssemblyCopyright line in the shared properties file. I've tried a couple ways that haven't worked. First:

[assembly: AssemblyCopyright(string.Format("Copyright © {$0} Acme, Inc.", Acme.FirstPublicationYear))]

... which tells me FirstPublicationYear does not exist in the namespace Acme . So I thought maybe I'd make it look more like an attribute:

[assembly: AssemblyCopyright(string.Format("Copyright © {$0} Acme, Inc.", [assembly: Acme.FirstPublicationYear]))]

... which tells me "Invalid expression term '['".

Is there a way to accomplish what I'm trying to do here? Thanks.

Instead of using string.Format , just try concatenating it:

"Copyright" + Acme.AssemblyInfo.FirstPublicationYear + "Acme Inc."

The compiler will be able to make a compile time constant from this.

There is no good way to accomplish this using code . The reason is that Attributes must have compile-time values to properly output the data to the resulting file, and there is thus no way to logically build them from parts, because that build is by definition a run-time, not compile-time, operation.

EDIT: It does turn out to be possible to concatenate strings using + operators, even at compile time, so long as all the strings being concatenated are themselves constant. See Frank's answer.

However, because all these values come from a single shared file, it is possible to do this by writing a prebuild batch file. I have implemented this as far as production code as a simple call in the prebuild step, with said helper being written in C#. As long as the output file (usually AssemblyInfo.cs ) is ignored by your repo (and if you're not using a repo, switch to one) you'll be able to rely on that file being generated by the prebuild, and then found by the compiler, even though it's not actually being copied down.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM