C# 两种类型的变量

C# 两种类型的变量,c#,json,typescript,json-deserialization,C#,Json,Typescript,Json Deserialization,我需要从TypeScript中读取一个JSON对象,它有一个变量名prop,它有两种类型,标识符或C的表达式。TypeScript可以有一个具有多个类型的变量,其union类型特性,例如,prop定义为 var property:Identifier | Expression 我正在用JsonConvert.DeserializeObject从C读取JSON对象字符串,例如 我应该如何在C中声明两种类型的变量?或者我应该只使用object,即声明为object属性吗?如果属性可以具有以下两种格

我需要从TypeScript中读取一个JSON对象,它有一个变量名prop,它有两种类型,标识符或C的表达式。TypeScript可以有一个具有多个类型的变量,其union类型特性,例如,prop定义为

var property:Identifier | Expression
我正在用JsonConvert.DeserializeObject从C读取JSON对象字符串,例如


我应该如何在C中声明两种类型的变量?或者我应该只使用object,即声明为object属性吗?

如果属性可以具有以下两种格式之一:

{ "prop": "identifier" }
{ "prop": { "complex": "object" } }
无论是简单字符串还是更复杂的对象,您都可以通过使用dynamic接受解析的prop值,并使用额外的属性返回标识符或复杂对象来解决此问题。下面是一个程序,演示:

void Main()
{
    var jsonStrings = new[]
    {
        "{ \"prop\": \"identifier\" }",
        "{ \"prop\": { \"complex\": \"object\" } }"
    };

    jsonStrings.Select(json => JsonConvert.DeserializeObject<Test>(json)).Dump();
}

public class Test
{
    public Test()
    {
        _Complex = new Lazy<Complex>(GetComplex);
    }

    [JsonProperty("prop")]
    public dynamic prop { get; set; }

    [JsonIgnore]
    public string Identifier => prop as string;

    private readonly Lazy<Complex> _Complex;

    [JsonIgnore]
    public Complex Complex => _Complex.Value;

    private Complex GetComplex()
    {
        if (!(prop is JObject))
            return null;

        return ((JObject)prop).ToObject<Complex>();
    }
}

public class Complex
{
    public string complex { get; set; }
}
输出:

另一种方法是创建您自己的类型来处理多个输出,然后再次使用辅助属性来评估您从json中实际获得的内容:

void Main()
{
    var jsonStrings = new[]
    {
        "{ \"prop\": \"identifier\" }",
        "{ \"prop\": { \"complex\": \"object\" } }"
    };

    jsonStrings.Select(json => JsonConvert.DeserializeObject<Test>(json)).Dump();
}

public class Test
{
    [JsonProperty("prop")]
    public dynamic prop { get; set; }

    [JsonIgnore]
    public PropertyValue Property
    {
        get
        {
            if (prop is string)
                return new IdentifierProperty(prop as string);
            return new ExpressionProperty(((JObject)prop).ToObject<Expression>());
        }
    }
}

public abstract class PropertyValue
{
}

public class IdentifierProperty : PropertyValue
{
    public IdentifierProperty(string identifier)
    {
        Identifier = identifier;
    }

    public string Identifier { get; }

    public override string ToString() => Identifier;
}

public class ExpressionProperty : PropertyValue
{
    public ExpressionProperty(Expression expression)
    {
        Expression = expression;
    }

    public Expression Expression { get; }

    public override string ToString() => Expression.ToString();
}

public class Expression
{
    public string complex { get; set; }

    public override string ToString() => $"complex: {complex}";
}
输出:


在执行JsonConvert.DeserializeObject时,需要对象的实际类型。一般来说,C是一种强类型语言,没有什么比这两种类型的变量更好的了。在某些情况下,您可以使用对象,也可以使用动态,但它们以后可能会导致其他问题。对于您的情况,您可以创建包含这两种类型的包装器类型,并从JavaScript填充所需的类型,但如果没有完整的上下文,则很难提出建议。谢谢,您还可以看到哪些类型的其他问题?所有这些都会导致类型安全性的丧失,例如运行时的类型不匹配。对于JsonConvert.DeserializeObject,您可以使用,但在不知道类型的情况下,我想这会很困难。这里没有JSON对象,您能澄清标识符或表达式的含义吗?我怀疑其中一个并没有真正遵循JSON语法。你能给出这两种方法的例子吗?谢谢,让我稍后在测试方法后回复你
void Main()
{
    var jsonStrings = new[]
    {
        "{ \"prop\": \"identifier\" }",
        "{ \"prop\": { \"complex\": \"object\" } }"
    };

    jsonStrings.Select(json => JsonConvert.DeserializeObject<Test>(json)).Dump();
}

public class Test
{
    [JsonProperty("prop")]
    public dynamic prop { get; set; }

    [JsonIgnore]
    public PropertyValue Property
    {
        get
        {
            if (prop is string)
                return new IdentifierProperty(prop as string);
            return new ExpressionProperty(((JObject)prop).ToObject<Expression>());
        }
    }
}

public abstract class PropertyValue
{
}

public class IdentifierProperty : PropertyValue
{
    public IdentifierProperty(string identifier)
    {
        Identifier = identifier;
    }

    public string Identifier { get; }

    public override string ToString() => Identifier;
}

public class ExpressionProperty : PropertyValue
{
    public ExpressionProperty(Expression expression)
    {
        Expression = expression;
    }

    public Expression Expression { get; }

    public override string ToString() => Expression.ToString();
}

public class Expression
{
    public string complex { get; set; }

    public override string ToString() => $"complex: {complex}";
}