You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何对无共同接口的动态类型进行静态类型检查?

Great question! When you're stuck with external classes you can't modify that share a method signature but don't implement a common interface, using dynamic works but exposes you to annoying runtime errors. Let's cover two solid approaches to add static type checking here:

This approach gives you strict compile-time validation by creating a common interface and wrapping your external types to fit it—no modifications to the original classes needed.

First, define an interface that matches the shared method signature:

public interface IHasError
{
    string getError();
}

Next, create adapter wrappers for each external class, plus implicit operators to let the compiler automatically convert instances of A/B to IHasError:

public static class ErrorAdapters
{
    // Wrapper for class A
    private class AErrorWrapper : IHasError
    {
        private readonly A _instance;
        public AErrorWrapper(A instance) => _instance = instance;
        public string getError() => _instance.getError();
    }

    // Wrapper for class B
    private class BErrorWrapper : IHasError
    {
        private readonly B _instance;
        public BErrorWrapper(B instance) => _instance = instance;
        public string getError() => _instance.getError();
    }

    // Implicit conversion for A → IHasError
    public static implicit operator IHasError(A instance)
    {
        return new AErrorWrapper(instance);
    }

    // Implicit conversion for B → IHasError
    public static implicit operator IHasError(B instance)
    {
        return new BErrorWrapper(instance);
    }
}

Now rewrite your utility function to accept IHasError instead of dynamic:

void printError(IHasError obj)
{
    Console.WriteLine("Error: {0}", obj.getError());
}

How it works:

  • When you pass an instance of A or B to printError, the compiler automatically uses the implicit conversion to wrap it in an adapter.
  • If you try to pass a class C (without a getError method), the compiler will throw an error immediately—no runtime surprises.

2. Generic + Pre-Flight Type Validation (Lightweight, Pseudo Compile-Time)

If you want to avoid writing wrappers, this approach uses generics and reflection to validate types once (on first use) instead of letting errors slip to runtime. It's not strict compile-time checking, but it catches issues much earlier than raw dynamic.

public static class ErrorPrinter
{
    // Cache valid types to avoid repeated reflection checks
    private static readonly HashSet<Type> _validatedTypes = new HashSet<Type>();

    static ErrorPrinter()
    {
        // Pre-validate your known good types upfront
        ValidateType<A>();
        ValidateType<B>();
    }

    private static void ValidateType<T>()
    {
        var getErrorMethod = typeof(T).GetMethod("getError", Type.EmptyTypes);
        if (getErrorMethod == null || getErrorMethod.ReturnType != typeof(string))
        {
            throw new InvalidOperationException(
                $"Type {typeof(T)} doesn't implement the required string getError() method."
            );
        }
        _validatedTypes.Add(typeof(T));
    }

    public static void PrintError<T>(T obj)
    {
        if (!_validatedTypes.Contains(typeof(T)))
        {
            ValidateType<T>();
        }
        Console.WriteLine("Error: {0}", obj.getError());
    }
}

How it works:

  • Known valid types (A/B) are validated once during static constructor initialization.
  • If you pass a bad type like C, the first call to PrintError<C> will throw an exception immediately, rather than failing mid-execution later.

内容的提问来源于stack exchange,提问作者Jake Cobb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:17:34