If you use LINQ expressions, you can pull out the information via reflection with slightly different syntax (and you get to avoid defining an extension method on a commonly used string type):
public class StringLength : Attribute
{
    public int MaximumLength;
    public static int Get<TProperty>(Expression<Func<TProperty>> propertyLambda)
    {
        MemberExpression member = propertyLambda.Body as MemberExpression;
        if (member == null)
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a method, not a property.",
                propertyLambda.ToString()));
        PropertyInfo propInfo = member.Member as PropertyInfo;
        if (propInfo == null)
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a field, not a property.",
                propertyLambda.ToString()));
        var stringLengthAttributes = propInfo.GetCustomAttributes(typeof(StringLength), true);
        if (stringLengthAttributes.Length > 0)
            return ((StringLength)stringLengthAttributes[0]).MaximumLength;
        return -1;
    }
}
So your Person class might be:
public class Person
{
    [StringLength(MaximumLength=1000)]
    public string Name { get; set; }
    public string OtherName { get; set; }
}
Your usage might look like:
Person person = new Person();
int maxLength = StringLength.Get(() => person.Name);
Console.WriteLine(maxLength); //1000
maxLength = StringLength.Get(() => person.OtherName);
Console.WriteLine(maxLength); //-1
You can return something other than -1 for a property that didn't have that attribute defined. You weren't specific, but that's easy to change.