Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.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# 使用未知数量的未知类型-.NET_C#_.net_Generics_Types - Fatal编程技术网

C# 使用未知数量的未知类型-.NET

C# 使用未知数量的未知类型-.NET,c#,.net,generics,types,C#,.net,Generics,Types,嘿,伙计们,我已经把一些复杂的需求转移到我需要知道的核心 我想向一个方法发送一组值,在该方法中,我想根据一个实体的属性来测试该值。属性将始终与值的类型相同 我还想测试值是null还是默认值,这显然取决于值类型是引用类型还是值类型 现在,如果发送到该方法的所有值都是相同类型的,那么我可以使用泛型很容易地做到这一点,如下所示: public static void testGenerics<TValueType>(List<TValueType> Values) {

嘿,伙计们,我已经把一些复杂的需求转移到我需要知道的核心

我想向一个方法发送一组值,在该方法中,我想根据一个实体的属性来测试该值。属性将始终与值的类型相同

我还想测试值是null还是默认值,这显然取决于值类型是引用类型还是值类型

现在,如果发送到该方法的所有值都是相同类型的,那么我可以使用泛型很容易地做到这一点,如下所示:

public static void testGenerics<TValueType>(List<TValueType> Values) {

        //test null/default
        foreach (TValueType v in Values) {
            if (EqualityComparer<TValueType>.Default.Equals(v, default(TValueType))) {
                //value is null or default for its type
            } else {
                //comapre against another value of the same Type
                if (EqualityComparer<TValueType>.Default.Equals(v, SomeOtherValueOfTValueType)) {
                    //value equals
                } else {
                    //value doesn't equal
                }
            }
        }
    }
我想这可能行得通

现在,我如何才能成功地比较同一类型的两个值,而不知道它们的类型成功且可靠?

简短的答案是“是”,但较长的答案是,这是可能的,但需要您付出不小的努力和一些假设才能使其工作。当在强类型代码中进行比较时,值被认为是“相等”的,但引用不相等时,问题就出现了。最大的问题是值类型,因为值为
1
的装箱
int
与另一个相同值的装箱
int
的引用不相等

考虑到这一点,您必须继续使用像
IComparable
接口这样的东西。如果您的类型总是特别匹配,那么这可能就足够了。如果其中一个值实现了
IComparable
,则可以转换到该接口并与其他实例进行比较以确定相等性(
==0
)。如果两者都没有实现它,那么您可能不得不依赖于引用平等。对于引用类型,除非存在自定义比较逻辑(例如,类型上的重载
=
运算符),否则这将起作用

请记住,这些类型必须完全匹配。换句话说,
int
short
不一定会这样比较,
int
double
也不一定会这样比较


您还可以使用反射来动态调用运行时由提供的
type
变量确定的泛型类型的
Default
属性,但如果我不必这样做以确保性能和编译时安全(或缺乏安全性),我就不想这样做原因。

您需要测试预定义列表的类型列表吗?如果是这样的话,您可以使用(甚至可能不使用,因为我们有泛型)。在实体上创建一个方法(可以使用分部类完成),该方法接受接口。然后,您的类在传递自身的接口上调用一个方法。接口方法可以是泛型的,也可以为要测试的每个类型创建重载

电池即将耗尽,否则将给出示例


点击“保存”15秒后,机器进入休眠状态

仔细考虑后,访问者模式可能无法解决您的特定问题。我以为您正在尝试比较实体,但似乎您正在测试值(因此可能是int和字符串)

但是为了完整起见,因为一旦你意识到访问者模式的作用,它就有点酷了,这里有一个解释

Visitor模式允许您处理多个类型,而无需弄清楚如何转换为特定类型(您使用该类型将类型与项解耦)。它通过两个界面工作-访问者和接受者:

interface IAcceptor
{
  void Accept(IVisitor visitor);
}

interface IVisitor
{
  void Visit(Type1 type1);
  void Visit(Type2 type2);
  .. etc ..
}
您可以选择在此处使用通用方法:

interface IVisitor
{
  void Visit<T>(T instance);
}
因为实现Accept()的类型知道它是什么类型,所以使用了正确的重载(或泛型类型)。您可以通过反射和查找表(或select语句)实现同样的效果,但这要干净得多。此外,您不必在不同的实现之间重复查找——不同的类可以实现IVisitor来创建特定于类型的功能

访问者模式是执行“双重分派”的一种方式。答案是另一种方式,你可以把它变形成适合你具体情况的东西


基本上,你的问题没有答案,很抱歉。:)不过,这个问题引起了我的兴趣——比如如何知道应该测试实体上的哪个属性?

Object.Equals(Object left,Object right)
静态方法,它内部依赖于提供的参数之一提供的
Equals(Object)
实现。你为什么不使用它

实施平等成员的规则大致如下:

  • 必需:重写
    Equals(object)
    GetHashCode()
    方法
  • 可选:为您的类型实现
    IEquatable
    (这是
    EqualityComparer.Default
    所依赖的)
  • 可选:实现==和!=操作员
  • 如您所见,如果您依赖于
    object.Equals(object left,object right)
    ,这将是依赖于等式实现模式中强烈要求的部分的最佳解决方案

    此外,它将是最快的选择,因为它只依赖于虚拟方法。否则你无论如何都会有一些反思

    public static void TestGenerics(IList values) {
      foreach (object v in values) {
        if (ReferenceEquals(null,v)) {
          // v is null reference
        }
        else {
          var type = v.GetType();
          if (type.IsValueType && Equals(v, Activator.CreateInstance(type))) {
            // v is default value of its value type
          }
          else {
            // v is non-null value of some reference type
          }
        }
      }
    }
    

    谢谢你,亚当!是的,被比较的类型总是完全相同的。IComparable可能是一个不错的选择,尽管我没有意识到这一点。你能提供一个简短的代码片段让我开始吗。另外,这种方法会考虑可空类型吗?嘿,Adam…现在我想起来了,我不确定如何实现IComparable。我使用的是LINQ2SQL实体,它们没有实现该接口。我传入的值能实现它吗?如何实现?是的,你会在单个值上使用IComparable,而不是实体本身。哈哈,没问题,Talljoe,谢谢你的提醒。我正在试着在mo反思,但是如果你能提供一个前男友
      void Accept(IVisitor visitor)
      {
        visitor.Visit(this);
      }
    
    public static void TestGenerics(IList values) {
      foreach (object v in values) {
        if (ReferenceEquals(null,v)) {
          // v is null reference
        }
        else {
          var type = v.GetType();
          if (type.IsValueType && Equals(v, Activator.CreateInstance(type))) {
            // v is default value of its value type
          }
          else {
            // v is non-null value of some reference type
          }
        }
      }
    }