Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这在C#中可能吗?_C#_Reflection - Fatal编程技术网

这在C#中可能吗?

这在C#中可能吗?,c#,reflection,C#,Reflection,我有一个测试扩展方法,因此我可以这样做: var steve = new Zombie(); steve.Mood.ShouldBe("I'm hungry for brains!"); 扩展方法: public static void ShouldBe<T>(this T actual, T expected) { Assert.That(actual, Is.EqualTo(expected)); } 在扩展方法中,有没有什么可以用来获取属性“BrainsConsum

我有一个测试扩展方法,因此我可以这样做:

var steve = new Zombie();
steve.Mood.ShouldBe("I'm hungry for brains!");
扩展方法:

public static void ShouldBe<T>(this T actual, T expected)
{
    Assert.That(actual, Is.EqualTo(expected));
}
在扩展方法中,有没有什么可以用来获取属性“BrainsConsumed”的名称的方法?奖励点是实例变量和类型Zombie

更新:

新的目标应该是:

public static void ShouldBe<T>(this T actual, T expected)
{
    var frame = new StackTrace(true).GetFrame(1);
    var fileName = frame.GetFileName();
    var lineNumber = frame.GetFileLineNumber() - 1;
    var code = File.ReadAllLines(fileName)
        .ElementAt(lineNumber)
        .Trim().TrimEnd(';');

    var codeMessage = new Regex(@"(^.*)(\.\s*ShouldBe\s*\()([^\)]+)\)").Replace(code, @"$1 should be $3");

    var actualMessage = actual.ToString();
    if (actual is string)
        actualMessage = "\"" + actual + "\"";

    var message = string.Format(@"{0} but was {1}", codeMessage, actualMessage);

    Assert.That(actual, Is.EqualTo(expected), message);
}

谢谢大家,尤其是马特·多森,这太棒了。顺便说一句,不要喂那些柔滑的巨魔。

不幸的是,在这个位置上,你将无法在那个阶段获得财产的名称。问题是,您正在传入BrainsConsumed字段的值,而此时根本没有指向僵尸的链接(就您的方法而言,它是一个int,无法计算int最初来自何处)


我能为您提供的最好的东西是Environment.StackTrace中会包含相关信息,因为您已经调用了steve.BrainsConsumed 1 step up The stack(仅当您试图做的是了解单元测试中失败的部分时,才建议使用此选项,而不是在常规程序流中实际遍历堆栈时)不,我想你不行

让我们假设BrainsConsumed是一个整数(看起来很可能)。在这种情况下,参数是通过值传递的——您得到的只是正在测试的整数的副本。除了本地范围(实际)中的名称外,它没有其他名称

这个类似的问题可以澄清:


这将允许您测试它,但无法获得方法的名称

您可以使用此扩展:

public static void ShouldBe<T>(this Func<T> func, T expected)
{
    Assert.AreEqual(func(), expected);
}
public static void应该是(应该是这个函数)
{
Assert.AreEqual(func(),应为);
}
使用以下ussage:

((Func<int>)Program.TestMethod).ShouldBe(2);
((Func)Program.TestMethod).应该是(2);

我能做的最好的事情是:

steve.Property(p => p.BrainsConsumed).ShouldBe(0);
或:

或:

关于:

奖励点数将是实例变量

通过使用
Expression
(或仅使用
Expression
),您可以相当轻松地获得属性名称和值。我将为中间部分做一个示例-注意,第一个示例需要DSL的额外类型,但没有什么繁重的内容:

public static class Test
{
    public static void AssertEqual<TSource, TValue>(
        this TSource source,
        Expression<Func<TSource, TValue>> selector,
        TValue expected)
        where TSource : class
    {
        TValue value = selector.Compile()(source);
        string paramName = selector.Parameters[0].Name;

        System.Diagnostics.Debug.Assert(
            EqualityComparer<TValue>.Default.Equals(value, expected),
            typeof(TSource) + " " + paramName + ": " +
                value + " doesn't match expected " + expected);
    }
}
公共静态类测试
{
公共静态无效资产相等(
这是来源,,
表达式选择器,
t预期值)
where TSource:class
{
TValue=selector.Compile()(源代码);
字符串paramName=选择器。参数[0]。名称;
System.Diagnostics.Debug.Assert(
EqualityComparer.Default.Equals(值,预期值),
typeof(TSource)+“+paramName+”:“+
值+“与预期值不匹配”+预期值);
}
}
或者稍微好一点的信息:

public class Zombie
{
    public int BrainsConsumed { get; set; }
    static void Main() {
        Zombie steve = new Zombie { BrainsConsumed = 2 };
        Test.ShouldBeEqual(() => steve.BrainsConsumed, 0);
    }

}
public static class Test
{
    static string GetName(Expression expr)
    {
        if (expr.NodeType == ExpressionType.MemberAccess)
        {
            var me = (MemberExpression)expr;
            string name = me.Member.Name, subExpr = GetName(me.Expression);
            return string.IsNullOrEmpty(subExpr)
                ? name : (subExpr + "." + name);
        }
        return "";
    }
    public static void ShouldBeEqual<TValue>(
        Expression<Func<TValue>> selector,
        TValue expected)
    {
        TValue value = selector.Compile()();

        string name = GetName(selector.Body);

        System.Diagnostics.Debug.Assert(
            EqualityComparer<TValue>.Default.Equals(value, expected),
            typeof(TValue) + " " + name + ": " +
                value + " doesn't match expected " + expected);
    }
}
公共类僵尸
{
public int BrainsConsumed{get;set;}
静态void Main(){
僵尸史蒂夫=新僵尸{BrainsConsumed=2};
测试。应该是相等的(()=>steve.BrainsConsumed,0);
}
}
公共静态类测试
{
静态字符串GetName(表达式expr)
{
if(expr.NodeType==ExpressionType.MemberAccess)
{
var me=(MemberExpression)expr;
string name=me.Member.name,subExpr=GetName(me.Expression);
返回字符串.IsNullOrEmpty(subExpr)
?名称:(子表达式+“+”名称);
}
返回“”;
}
公共静态空间应该相等(
表达式选择器,
t预期值)
{
TValue=selector.Compile();
string name=GetName(selector.Body);
System.Diagnostics.Debug.Assert(
EqualityComparer.Default.Equals(值,预期值),
typeof(TValue)+“名称+”:“+
值+“与预期值不匹配”+预期值);
}
}

如果代码是调试生成的,可以使用一些诊断类来获取代码。考虑到这是针对单元测试的,调试可能是合理的

public static void ShouldBe<T>(this T actual, T expected)
}

例如,code=“steve.BrainsConsumed.ShouldBe(0);”


显然,您应该在此代码中添加一些错误检查,如果不读取文件中的所有行,您可能会加快检查速度。

我不太明白为什么您会发布如此混乱且难以理解的代码,如果可以的话,这通常是一种不好的做法。但每个人都有自己的;这似乎有点不负责任。作为一个学习过程,这很好,但如果有人真的这样做了,他们应该被枪毙…@silky:哪一部分很难理解,你会如何让它更简单?呃。。。因为这是从代码表达式中获取属性名和/或变量名的最可靠的方法?Yuriy:我不打算解释对有能力自己解决它的人来说显而易见的事情。hmemcpy:我不会尝试解决它(因此我没有)。这不是一个合适的问题;我几乎可以肯定(尽管我可能是错的)这是没有合法用途的,而且基本目标可以以更好的方式实现。如果其他人对使用它感兴趣(你为什么不感兴趣!)
Assert.AreEqual(() => steve.BrainsConsumed, 0);
public static class Test
{
    public static void AssertEqual<TSource, TValue>(
        this TSource source,
        Expression<Func<TSource, TValue>> selector,
        TValue expected)
        where TSource : class
    {
        TValue value = selector.Compile()(source);
        string paramName = selector.Parameters[0].Name;

        System.Diagnostics.Debug.Assert(
            EqualityComparer<TValue>.Default.Equals(value, expected),
            typeof(TSource) + " " + paramName + ": " +
                value + " doesn't match expected " + expected);
    }
}
public class Zombie
{
    public int BrainsConsumed { get; set; }
    static void Main() {
        Zombie steve = new Zombie { BrainsConsumed = 2 };
        Test.ShouldBeEqual(() => steve.BrainsConsumed, 0);
    }

}
public static class Test
{
    static string GetName(Expression expr)
    {
        if (expr.NodeType == ExpressionType.MemberAccess)
        {
            var me = (MemberExpression)expr;
            string name = me.Member.Name, subExpr = GetName(me.Expression);
            return string.IsNullOrEmpty(subExpr)
                ? name : (subExpr + "." + name);
        }
        return "";
    }
    public static void ShouldBeEqual<TValue>(
        Expression<Func<TValue>> selector,
        TValue expected)
    {
        TValue value = selector.Compile()();

        string name = GetName(selector.Body);

        System.Diagnostics.Debug.Assert(
            EqualityComparer<TValue>.Default.Equals(value, expected),
            typeof(TValue) + " " + name + ": " +
                value + " doesn't match expected " + expected);
    }
}
public static void ShouldBe<T>(this T actual, T expected)
var frame = new StackTrace(true).GetFrame(1);
var fileName = frame.GetFileName();
var lineNumber = frame.GetFileLineNumber() - 1;

string code = File.ReadLines(fileName).ElementAt(lineNumber).Trim();

Debug.Assert(actual.Equals(expected), code);