【问题标题】:Any way to use interfaces as "type aliases" in C#?在 C# 中使用接口作为“类型别名”的任何方式?
【发布时间】:2026-02-12 00:40:02
【问题描述】:

基本上我想使用我自己的类型而不是像 int/double 这样的原始类型,但仍然传递这些原始值。比如:

interface IInt {} // My interface to represent int. If I could fake so "int" implements this, all would work.

interface IPostNumber : IInt {} // Post number is an int. But int is not type safe enough for me.

void MyFunction(IPostNumber postNumber); // My function that should accept int/IPostNumber.

MyFunction(42); // This could also work with implicit conversion, but not allowed for interfaces:(

【问题讨论】:

  • 我认为您正在寻找所谓的“使用别名指令”。
  • 使用 IPostNumber = System.Int32;使用 IAccountNumber = System.Int32;可以使用,但类型系统不会确保 IAccountNumber 不作为 IPostNumber 传递。而且我还想将该接口用于其他接口的东西。
  • 您需要解决什么具体问题?这似乎是一种过度思考。
  • 问题:为什么要使用自定义接口而不是像int、double等值类型?

标签: c# interface primitive type-safety type-alias


【解决方案1】:

我认为您可能正在寻找的是隐式运算符,但不幸的是,我认为 C# 语言规范中的接口不支持它们。如果需要,您可以使用子类执行此操作。这是一个例子:

public class MyInt
{
   int SomeValue;
   public TestInt(int i)
   {
       SomeValue = i;
   }

   public static implicit operator MyInt(int i)
   {
       return new MyInt(i);
   } 

   public static implicit operator int(MyInt myInt)
   {
       return myInt.SomeValue;
   }
}

要使用隐式运算符进行赋值,您可以这样做:

MyInt n = 3;
int x = n;

见:implicit operator using interfaces

【讨论】:

  • 我在 ispiro 的建议下使用了隐式运算符,它们似乎可以解决问题。
【解决方案2】:

根据 ispiro 的建议,我发现了应该涵盖所有内容的内容。

所以我声明我的接口独立于底层表示,例如

public interface IPostNumber{}
public interface IPostNumberFrom : IPostNumber{}
public interface IPostNumberTo : IPostNumber{}

这些具有完整的接口通用性,例如多重继承。然后用隐式转换的泛型类完成数据表示:

public class CInt<T>
        {
            public int value;
            public static implicit operator int(CInt<T> d) => d.value;
            public static implicit operator CInt<T>(int b) => new CInt<T>() { value = b };
        }

接受IPostNumberint 的函数是这样完成的:

    private int TestPostNumberInt(CInt<IPostNumber> i) => i;
    private int TestPostNumberFrom(CInt<IPostNumberFrom> i) => i;

        CInt<IPostNumber> a = 4; // Works
        Assert.Equal(1, TestPostNumberInt(1));  // Works
        Assert.Equal(1, TestPostNumberFrom(a)); // Don't compile with IPostNumber into IPostNumberFrom

现在我可以随时声明CString&lt;IPostNumber&gt;,如果某些帖子编号用字符串表示。或者一个函数可以接受IPostNumber 接口本身,如果我做一些类的话。现在有个小问题是,如果我想将CInt&lt;IPostNumberFrom&gt; 传递给TestPostNumber,方法必须与T : IPostNumber 通用,像这样:

    private int TestPostNumberInt<T>(CInt<T> i) where T : IPostNumber => i;
    private int TestPostNumberIntFrom<T>(CInt<T> i) where T : IPostNumberFrom => i;

然后在使用隐式转换时不会检测到泛型类型(必须强制转换)。但我们会看看这是否有什么大不了的。

也供以后考虑:我将拥有class CJSON&lt;T&gt; : CString&lt;T&gt;。从我看到它的工作原理来看,尽管CJSON 也可以有不同的表示形式,比如在某些情况下byte[]。 (但这让事情走得很远)。所以只需要认真考虑我的领域概念的表示与接口。

【讨论】:

    【解决方案3】:

    你要找的是这个吗?

    public class IInt
    {
        public int TheInt;
    
        public IInt(int theInt)
        {
            TheInt = theInt;
        }
    }
    

    然后使用:

    IInt i = new IInt(42);
    MyFunction(i);
    

    或为int 定义MyFunction,然后使用:

    IInt i = new IInt(42);
    MyFunction(i.TheInt);
    

    还有一个想法:

    public class IInt<T> where T : struct
    {
        public T TheInt;
    
        public IInt(T theInt)
        {
            TheInt = theInt;
        }
    }
    

    【讨论】:

    • 使用类或结构的主要问题是,我以后也想通过接口继承它。我还希望避免用结构或类包装 int 的性能成本。
    • @user2154768 您可以定义一个接口并让IInt 实现它吗?也许再解释一下为什么你需要这个接口?你会用它做什么?
    • 至于性能,据我所知,如果您不打算在某个紧密的循环中多次使用它,那并不重要。但这当然取决于您的具体情况。
    • 我将设置继承,例如 IPostNumberFrom : IPostNumber : IInt,例如多层,多重继承。我还可以使用单独的空 IPostNumber 接口,使用 IPostNumberInt : IPostNumber,Int 和 IPostNumberString : IPostNumber,IString。我将使用反射来读取我的接口并生成一些图形,通过使用反射查找我的所有函数,我将使用这些图形来查找从一种类型转换为另一种类型的函数路径。然后可能会生成一些代码来生成路径的有效实现。 B计划是函数参数/返回属性...
    • @user2154768 好的。所以我没有想法:)。但我确实在我的回答中发布了另一个想法 - 使课程通用。祝你好运!
    【解决方案4】:

    您可以创建一个扩展方法,但该方法应该被显式调用。

    【讨论】:

      最近更新 更多