2014-11-08 38 views
1

我想做一个像下面这样的函数。 KL是泛型类型参数。 (这是在万一你不知道的MultiKeyDictionary by Aron Weiler定制)对值类型和引用类型使用不同的函数签名

protected void Dissociate(K primaryKey, L subKey) 
{ 
    primaryToSubkeyMapping.Remove(primaryKey??subDictionary[subKey]); 
    subDictionary.Remove(subKey??primaryToSubkeyMapping[primaryKey]); 
} 

每个参数是可选的,但至少一个必须存在; null意味着缺席。问题是,如果泛型参数是一个值类型,我需要用Nullable包装函数的参数,所以primaryKey??是有效的,所以我可以通过null指定参数的缺席。但是,如果K是引用类型,则Nullable<K>也是无效的!

那么,我可以以某种方式编写实现,因此它对两种情况都有效吗?

+0

请注意,我确实需要将值类型包装到'Nullable'中。我编辑了这个问题来强调这一点。 – 2014-11-08 10:48:46

+1

你想让它们为空,并且同时传递引用类型?如果是这样,这是不可能的,为了使它们成为'Nullable ',你必须添加'where T:struct'约束。 – 2014-11-08 10:50:55

+0

那么,我可以制作两个方法实现,以便根据约束是否适用来使用适当的方法吗? – 2014-11-08 10:58:58

回答

0

博顿线:这可以完成,但需要不成比例的额外开销。所以这是完全不切实际的。

最后,我通过添加两个没有任何参数的重载方法来解决这个问题。


根据C# specification v.3.0,§B.2.7,类型约束也可以放在单个方法上。但是,这些方法需要将约束条件类型放在上作为它们自己的类型参数。所以,我能够做的伎俩是这样的:

protected void Dissociate<KP,LP>(KP? primaryKey, LP? subKey) 
    where KP:struct,K where LP:struct,L 
{ 
    primaryToSubkeyMapping.Remove(primaryKey??subDictionary[subKey.Value]); 
    subDictionary.Remove(subKey??primaryToSubkeyMapping[primaryKey.Value]); 
} 

但是,现在,我需要让实现为classstruct每个组合!当我尝试在typeof(K).IsValueType类似的检查中调用它们时,编译器无法将其作为重载解析的提示并产生相应的错误。对它们进行不同的命名只会更进一步:编译器不相信只有其中一个在任何具体实现中被调用,并且仍然失败参数类型检查。现在有两种选择:

  • 通过反思调用相关实现。获取GetMethod()的泛型类型参数对象,然后制定一个具体的方法将是一个PINA - 即使我通过不同的方式命名四个实现来简化前一步骤,

  • 制作四个派生类,每个派生类都有不同的名称。这会搞砸类层次结构。

    • 要解决层次分裂(以Liskov原则为代价),我可以创建另一个类,将其委托给其中的一个类。在相应的代码中,我将再次面对相同的类型检查问题,并且必须按照与前一项相同的方式来解决它们。

    简而言之,这种方式是完全无法使用的。

0

您可以指定Nullable<T>作为允许过载的参数类型。例如:

class A { } 
struct B { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     A a = new A(); 
     B? b = new B(); 

     Method(a); 
     Method(b); 

     a = null; 
     b = null; 

     Method(a); 
     Method(b); 
    } 

    static void Method<T>(T t) where T : class 
    { 
     Console.WriteLine("Reference type: " + (t != null ? "not " : "") + "null"); 
    } 

    static void Method<T>(Nullable<T> t) where T : struct 
    { 
     Console.WriteLine("Nullable<T> type: " + (t != null ? "not " : "") + "null"); 
    } 
} 

在你自己的情况下,如果类型参数KL可以是独立的引用类型或Nullable<T>,那么你就需要四载,采取一切可能的组合的照顾。

您应该可以让所有四个重载共享一个通用的实现,方法是处理每个重载中的空测试,然后调用一个不关心空值的共享实现方法(即可以安全地假定它们已被解决) 。

+0

在描述的步骤中,如果我尝试从同一泛型类中的其他代码调用它们,我遇到了无法告诉编译器重载方法的问题。 – 2014-11-08 18:51:53

+0

是的。这个问题并不清楚,调用者也是通用的。为了使重载解析起作用,编译器需要在编译时知道什么类型和约束在起作用,如果从通用类型调用而没有任何约束,这是不可能的。对于那个很抱歉。 – 2014-11-08 18:57:45

+0

我的方法被“保护”,这意味着几乎完全确定。但我没有强调这一点。 – 2014-11-08 19:07:25